Page 1 of 1

Indigo SDK Python Bindings

Posted: Thu Apr 26, 2012 3:16 am
by dougal2
Since I am no longer likely to use this code, I hereby release to the public domain my python bindings around the Indigo SDK. I'm not sure if usage or viewing of this code requires an Indigo Developer NDA, I reserve Glare Tech Ltd the right to re-license this code as they see fit at any time. This release does not directly contain any of the Indigo SDK code (though parts were 'inspired' by the Driver.cpp demo).

The last time this was built, it was for the Indigo SDK version 3.0.21 and python 3.2.0 on Windows - it also uses Boost 1.46 to create the actual binding code. I never attempted to compile for other OSs.

I had this running as a python module under Blender 2.5x for basic renderer integration. However, due to a fast moving Blender API target support was dropped in order to actually get the first Blendigo-2.5 release out on time.

Chances are it would need updating for more recent Indigo SDKs, but should give an idea of how creating such a binding works.

Cheers,
Doug.

Re: Indigo SDK Python Bindings

Posted: Thu Apr 26, 2012 3:17 am
by dougal2
.... and it appears that I cannot actually attach a file in this forum. I'll add the archive as soon as this is possible... ;)

Re: Indigo SDK Python Bindings

Posted: Thu Apr 26, 2012 4:00 am
by CTZn
dougal2 wrote:I hereby release to the public domain[...].
You Sir... thanks !

Would you recommend me to use such bindings, granted that the Maya API differs from blender's ? I may have to take the SDK jump sometime.

I do have a generic NDA active, dunno wether there is a specific one concerning the SDK.

Re: Indigo SDK Python Bindings

Posted: Thu Apr 26, 2012 4:06 am
by dougal2
There's nothing Blender-specific about this code, it's simply a way to invoke Indigo and get the image back using python code instead of launching an external process.

I've lost some of the sample/test python code I used to test this module, but I'll try to dig something out of the Blendigo history showing how to use it.

Re: Indigo SDK Python Bindings

Posted: Thu Apr 26, 2012 4:13 am
by CTZn
I would need more a thoroughfull example than a complete library, though I imagine that something extensive has to be relevant as a whole.

I am burning steps still.

On a personal note I'm glad about this position you found and I am hoping that the working environment is also comfortable for you.

Re: Indigo SDK Python Bindings

Posted: Thu Apr 26, 2012 4:29 am
by dougal2
Here are various parts of the python code I used in Blendigo for integrated rendering; this should be a complete example, however I haven't actually tested it

Code: Select all


#!/usr/env python

import indigo

# Utils

import threading

class TimerThread(threading.Thread):
	"""Periodically call self.kick(). The period of time in seconds
	between calling is given by self.KICK_PERIOD, and the first call
	may be delayed by setting self.STARTUP_DELAY, also in seconds.
	self.kick() will continue to be called at regular intervals until
	self.stop() is called. Since this is a thread, calling self.join()
	may be wise after calling self.stop() if self.kick() is performing
	a task necessary for the continuation of the program.
	The object that creates this TimerThread may pass into it data
	needed during self.kick() as a dict LocalStorage in __init__().
	
	"""
	STARTUP_DELAY = 0
	KICK_PERIOD = 8
	
	active = True
	timer = None
	
	LocalStorage = None
	
	def __init__(self, LocalStorage=dict()):
		threading.Thread.__init__(self)
		self.LocalStorage = LocalStorage
	
	def set_kick_period(self, period):
		"""Adjust the KICK_PERIOD between __init__() and start()"""
		self.KICK_PERIOD = period + self.STARTUP_DELAY
	
	def stop(self):
		"""Stop this timer. This method does not join()"""
		self.active = False
		if self.timer is not None:
			self.timer.cancel()
			
	def run(self):
		"""Timed Thread loop"""
		while self.active:
			self.timer = threading.Timer(self.KICK_PERIOD, self.kick_caller)
			self.timer.start()
			if self.timer.isAlive(): self.timer.join()
	
	def kick_caller(self):
		"""Intermediary between the kick-wait-loop and kick to allow
		adjustment of the first KICK_PERIOD by STARTUP_DELAY
		
		"""
		if self.STARTUP_DELAY > 0:
			self.KICK_PERIOD -= self.STARTUP_DELAY
			self.STARTUP_DELAY = 0
		
		self.kick()
	
	def kick(self):
		"""Sub-classes do their work here"""
		pass

# Rendering monitoring

def indigo_log(string):
	print(string)

def handler_LOG(msg):
	indigo_log('RENDERING: %s' % msg[:-1]) # Remove annoying extra \n from message
	return False
		
def handler_EVENT(msg):
	if msg == indigo.IndigoEventType.HALT_REQUESTED:
		indigo_log('Halt condition reached')
		return True
			
	return False
		
def handler_ERROR(msg):
	indigo_log('ERROR: %s' % msg)
	return True
		
class IndigoMessageThread(TimerThread):
	KICK_PERIOD = 0.5
			
	message_handlers = {
		indigo.indigo.IndigoMessageType.LOG:	handler_LOG,
		indigo.indigo.IndigoMessageType.EVENT:	handler_EVENT,
		indigo.indigo.IndigoMessageType.ERROR:	handler_ERROR,
	}
			
	def kick(self):
		msgs = self.LocalStorage['renderer'].get_messages()
		if len(msgs) > 0:
			stop = False
			for type, msg in msgs:
				if type in self.message_handlers.keys():
					if self.message_handlers[type](msg):
						stop = True
			
			if stop:
				self.stop()
		
class IndigoStatsThread(TimerThread):
	KICK_PERIOD = 0.5
	stats_string = ''
	def kick(self):
		self.stats_string = '%s | %0.2f kS/Sec | %0.2f Samples/Px' % (
			format_elapsed_time(self.LocalStorage['renderer'].get_render_time()),
			self.LocalStorage['renderer'].get_samples_per_second() / 1000.0,
			self.LocalStorage['renderer'].get_samples_per_pixel(),
		)
		indigo_log(self.stats_string)
		
class IndigoFramebufferThread(TimerThread):
	KICK_PERIOD = 30
	def kick(self):
		renderer = self.LocalStorage['renderer']
				
		xres, yres, combined = renderer.blenderCombinedRect(True) # RGC = True
				
		if xres > 0 and yres > 0 and len(combined) > 0:
			# Do something with the image data in combined variable
		else:
			indigo_log('Invalid framebuffer: %ix%ix%i' % (xres, yres, len(combined)))

# Rendering instance

renderer = indigo.Context(
	"PATH_TO_SDK_BINARIES",
	"PATH_TO_OUTPUT"
)

# Periodically get messages from Indigo's message queue
message_thread = IndigoMessageThread(
	{ 'renderer': renderer }
)

message_thread.start()

# Load the scene file into the renderer
if not renderer.load_igs("PATH_TO_IGS"):
	print("ERROR Loading scene.")
	exit()

# Start the rendering
renderer.build_scene()
renderer.start_rendering()

# Periodically print rendering stats/progress etc
stats_thread = IndigoStatsThread(
	{ 'renderer': renderer }
)

stats_thread.start()

# Periodically get the rendered image back from Indigo
framebuffer_thread = IndigoFramebufferThread(
	{ 'renderer': renderer }
)

framebuffer_thread.start()

# Wait for rendering to complete; this is detected by the message_thread terminating
while message_thread.isAlive():
	# wait; you could do other tasks here asynchronously as the render progresses....
	sleep(1)


# Clean up

stats_thread.stop()
stats_thread.join()
message_thread.stop()
message_thread.join()
framebuffer_thread.stop()
framebuffer_thread.join()
renderer = None

Re: Indigo SDK Python Bindings

Posted: Thu Apr 26, 2012 4:40 am
by dougal2
I uploaded the binding code to google docs, here's the link to download:

https://docs.google.com/open?id=0B35D3F ... 0FleXpmQWc

(this file can only be downloaded with this link, please keep it private until license terms are confirmed)

Re: Indigo SDK Python Bindings

Posted: Thu Apr 26, 2012 5:09 am
by CTZn
Got that.