Tag: purebasic

Embedding Python in PureBasic – Part 1

Posted by on December 24, 2012

The following is a bare-bones example of how to run a statement in python, from within PureBasic and then retrieve the result from Python. As said, the example has been stripped down for simplicity sake until you can get familiar with the Python API.

Requirements: python3.3, obtain it here.
The python33.lib file resides within Python33/python33.lib (assuming your install directory is Python33, of course)
On Windows, also, the python33.dll file resides in your system32 directory (at least for XP)

Import "python33.lib"
	Py_Initialize()
	Py_Finalize()
	PyRun_SimpleString( String.s )
	PyImport_AddModule( String.s )
	PyModule_GetDict( *PyModule.i )
	PyDict_GetItemString( *PyObject.i, Key.s )
	PyLong_AsLong( *PyObject.i )
EndImport

Define.i *module, *dictionary, *retval
If Py_Initialize()
	
	PyRun_SimpleString( "retval = 10+1*10-2*16/(2-3)" )	; let's run a basic mathematical expression, as a statement.
	
	*module	= PyImport_AddModule("__main__")		; Obtain a reference from main
	If *module 						; Did we get a reference to main?
		*dictionary = PyModule_GetDict(*module) 	; Let's get a reference of it's dictionary then.
		If *dictionary
			*retval = PyDict_GetItemString(*dictionary, "retval") ; Obtain a reference of retval
			If *retval
				Debug PyLong_AsLong(*retval)  	; Debug the result from the interpreter
				Debug 10+1*10-2*16/(2-3)	; Execute the same expression on native code
			EndIf
		EndIf
	EndIf
	
	Py_Finalize()
EndIf

The example above may look over-complicated, in fact we could get rid of most checks since we know there has to be a main and a dictionary as we already defined a variable… But, you have to write safe code and this implies always checking your pointers/handles.

At this point we haven’t defined any structures pertinent to Python nor have we set any variables within PB so that we may read them from Python itself, but that’s something we’ll discuss later.

Right now this code could serve you to execute simple scripts for your games or applications. For instance on an RPG game you could calculate a melee attack using a few fixed rules and then obtain the result on PB.

Have fun,
Cheers.

(PB) Timeout Library

Posted by on December 12, 2012

Intro

This simple “timeout” library allows you to easily perform timed operations in your games and applications. Thanks to the callbacks you can also perform arbitrary functions within each update cycle.

The library is very simple to use, you must define a maximum timeout period and an update rate when you create an instance of TIMEOUT.

The “maximum” is in milliseconds and corresponds to the timeout period, for example 1000 would be 1 second timeout.

The “update_rate” sets how many updates there will be within 0 and the “maximum” in this case 1000), if we were to use 10 updates then we would experience the callback to be called every 100ms.

Of course both the callback and the user variables are optional, but they’re a handy feature.
 

Simple use case:

Define.TIMEOUT *timeout = timeout_create( 1000 * 5, 100 ) ; 5 seconds maximum timeout, 100 updates a second.
If *timeout

	Debug "starting"
	Repeat
		timeout_update( *timeout )
		Debug "update"
	Until timeout_expired( *timeout )
	
	If timeout_expired( *timeout )
		Debug "timed out"
	EndIf
	
	timeout_destroy( *timeout )
EndIf

 
One of the many uses I have for this library includes waiting for a server to respond, sending timed events to clients, etc. I even use it to send notices to every client on the server before the server actually shuts down! (game server)
 
You can actually select whether the library should perform an actual sleep / delay operation to save cycles ( for example in cases where you have a waiting loop it’s ideal to sleep for a given period of time instead of wasting those cycles ) or you can have it compare old vs new time instead of performing a real delay. On timeout_update() the second parameter defines this behavior.
 

The library:

EnableExplicit

Structure TIMEOUT
	
	delay.i 			; based on how many updates a second are required, this holds the delay value in ms.
	current.i 			; the current timeout value in ms, this is the "counter" and uses the "delay" to increment.
	maximum.i 			; the timeout value in ms
	update_rate.i 			; holds the update speed in times per second
	
	old_time.i			; the old time in milliseconds
	new_time.i			; the new, current time in milliseconds
	
	*callback.i			; user callback pointer, we can't cast it as a timeout_callback prototype here for obvious reasons.
	user_variable.i			; a custom user variable, could be a pointer or anything at all, it's accessed through the instance ptr sent to the callback.
	
EndStructure

Prototype.i timeout_callback( *this.TIMEOUT )

Procedure.i timeout_create( maximum.i, update_rate.i, *callback.timeout_callback = #Null, UserVariable.i = #Null )
	
	Define.TIMEOUT *this = AllocateMemory( SizeOf(TIMEOUT) )
	; set all the pertinent values to this structure
	If *this
		With *this
			\maximum 	= maximum
			\update_rate 	= update_rate
			\delay		= ( 1000 / update_rate )
			\current	= 0
			\old_time	= 0
			\new_time	= 0
			\callback 	= *callback
			\user_variable 	= UserVariable
		EndWith
		
		ProcedureReturn *this
	EndIf
	
EndProcedure

Procedure.i timeout_destroy( *this.TIMEOUT )
	
	; check whether the pointer is not a null and proceed to free the memory.
	If *this
		FreeMemory( *this )
		ProcedureReturn 
	EndIf
	
EndProcedure

Procedure.i timeout_update( *this.TIMEOUT, Should_Delay.i = #True )
	
	If *this
		If Should_Delay
			
			Delay( *this\delay )
			*this\current + *this\delay
			ProcedureReturn *this\current
			
		Else
			
			*this\new_time = ElapsedMilliseconds() ; obtain the current time
			If *this\new_time > *this\old_time + *this\delay ; compare if the new time is bigger than the old time plus the delay factor
				; if so, update the old time with the new time and increase the current variable by the delay value.
				*this\old_time = *this\new_time
				*this\current + *this\delay
				; is there a callback? if so, call it.
				If *this\callback
					Define.timeout_callback *cb = *this\callback
					*cb( *this )
				EndIf
				; return the current value, in cases where the timeout has an update rate / interval of 1, we'll always get the full amount.
				ProcedureReturn *this\current
			EndIf
			
		EndIf
	EndIf
	
EndProcedure

Procedure.i timeout_reset( *this.TIMEOUT, WipeUserVal.i = #False )
	
	If *this
		; Wipe out the changing variables
		With *this
			\current	= 0
			\new_time	= 0
			\old_time	= 0
		EndWith
		; Optionally wipe out the user variable, this defaults to false.
		If WipeUserVal
			*this\user_variable = #Null
		EndIf
	EndIf
	
EndProcedure

Procedure.i timeout_expired( *this.TIMEOUT )
	
	; Has the timeout expired?, if so return true (1).
	If *this
		If *this\current => *this\maximum
			ProcedureReturn #True
		EndIf
	EndIf
	
EndProcedure

 

That’s all, enjoy!

If you have any comments, feel free to leave them here!
Any additions to the code will be welcomed.

Cheers.

 

(PB) Loading Assets, the simple way.

Posted by on January 23, 2012

Intro

Assets are an essential part of most games, how you manage them determines whether you spend more time working on them than dealing with them.

For small to medium games, loading an entire directory and having it referenced to a Map is the ideal solution. It’s both flexible and simple.

The following code allows you to do just this:

Prototype.i LOAD_DIRECTORY_CALLBACK( Map Assets.i(), directory.s, extension.s, name.s, userDefined.i = #Null )

Procedure.i LoadDirectory( Map assets.i(), directory.s, extension.s, *callback.LOAD_DIRECTORY_CALLBACK, userDefined.i = #Null )

	Define.i dir = ExamineDirectory( #PB_Any, directory, "*" + extension )
	If IsDirectory( dir )

		Define.i count = 0
		Define.s name = ""

		While NextDirectoryEntry( dir )
			If DirectoryEntryType( dir ) = #PB_DirectoryEntry_File
				name = DirectoryEntryName( dir );
				assets( ReplaceString( name, extension, "" ) ) = *callback( assets(), directory, extension, name, userDefined );LoadSound( #PB_Any, directory + "\" + name )
				count + 1
			EndIf
		Wend

		FinishDirectory( dir )
	EndIf
	ProcedureReturn count

EndProcedure

To use this code you must define a procedure of your own, this procedure is going to be called on each file to be loaded; you’ll have to load and process the file in this function.

Example use:

Global NewMap sprite.i()
Procedure.i callback_loadsprites( Map Assets.i(), directory.s, extension.s, name.s, userDefined.i = #Null )
	ProcedureReturn LoadSprite( #PB_Any, directory + "\" + name, userDefined )
EndProcedure

LoadDirectory( sprite(), "sprites", ".png", @callback_loadsprites() )

The example will attempt to scan through the directory “sprites”, it will execute your callback on each png file it finds inside the aforementioned directory, furthermore it’ll reference the filename (without extension) to the sprite() Map, so when you need a handle for the sprite called “fire.png” you’d just use sprite(“fire”) to obtain it.

Since the files are referenced to a Map by their actual name, you could easily implement a scripting system or any other dynamic management solution for your assets without much hassle.

An interesting part of the code is the return value, it’s actually the number of assets found (not the ones loaded, since your callback could choose not to load a certain file, for instance).

There are several limitations to this simple implementation, which is why I mentioned “small games” – There is no directory recursion, no advanced filtering options, no way to parallel the process on a separate thread and there’s no error handling at the moment.

However, it’s still very useful and I highly recommend you try it out, while it’s not a novel aproach, it’s always been the method I used to load my assets and it just works.

Have fun!

(PB) String Between Characters

Posted by on April 26, 2011

This is a small purebasic function used to retrieve a string between two known characters, it also allows you to provide a starting position.

Procedure.s str_between_char( *Source.CHARACTER, First.C, Last.C, StartAt.i = 0 )
	Define.i dwLength
	
	*Source + (StartAt * SizeOf(CHARACTER))
	Repeat
		If *Source\c = First ; If this character matches the First character
			*Source + SizeOf(CHARACTER)
			dwLength = *Source
			Repeat ; Repeat until we find an occurrance with the Last character
				*Source + SizeOf(CHARACTER)
			Until *Source\c = Last
			dwLength = (*Source - dwLength)
			ProcedureReturn PeekS( *Source - dwLength, dwLength ) ; Peek the output string
			Break
		EndIf
		*Source + SizeOf(CHARACTER)
	Until *Source\c = #Null
	
EndProcedure

Example use:

Define.s str 		= "dd(hallo)xyz(a)"
Define.s result 	= str_between_char(@str, '(', ')', 2)
Debug result

If you’re working on a parser or similar project this will sure come in handy.
Enjoy!

PB Parallel Port Library

Posted by on January 12, 2011

What is it:

This is a minimalist  library based on the inpout32 DLL

Basically I wrapped the original library and added a whole bunch of useful constants to easily access the Control and Status registers while keeping things clean and simple.

This library is currently being used on a side project I’ve been working on with a friend, since he doesn’t have any μController experience we decided to use LPT for the time being.

The code:


; 	Minimalist Library for Parallel port access based on inpout32.dll 
;		by Gustavo J. Fiorenza AKA GuShH (info@gushh.net - info@gushh.com.ar)
;		Version 1.0 - 11/01/2011

EnableExplicit

; Default LPT Addresses.
#PARALLEL_PORT_LPT1						= $3BC
#PARALLEL_PORT_LPT2						= $378
#PARALLEL_PORT_LPT3						= $278

; Register offsets.
#PARALLEL_PORT_STATUS						= $01
#PARALLEL_PORT_CONTROL						= $02

; Shared with Data Register.
#PARALLEL_PORT_OFF						= $00
#PARALLEL_PORT_BIT0						= $01
#PARALLEL_PORT_BIT1						= $02
#PARALLEL_PORT_BIT2						= $04
#PARALLEL_PORT_BIT3						= $08
#PARALLEL_PORT_BIT4						= $10
#PARALLEL_PORT_BIT5						= $20
#PARALLEL_PORT_BIT6						= $40
#PARALLEL_PORT_BIT7						= $80

XIncludeFile "ParallelPort_Constants.pbi" 	; All of the helper, non-essential constants are defined here.


Structure PARALLEL_PORT
	Handle.i
	Port.i
	LastData.i
EndStructure


;- Instance construction and destruction

Procedure.i ParallelPort_Create( Port.i = #PARALLEL_PORT_LPT2 )
	
	Define.PARALLEL_PORT *this = AllocateMemory( SizeOf(PARALLEL_PORT) )
	If *this
		
		*this\Port 	= port
		*this\Handle 	= OpenLibrary( #PB_Any, "inpout32.dll" )
		
		If IsLibrary( *this\Handle )
			ProcedureReturn *this
		Else
			Debug "Couldn't load inpout32.dll"
			FreeMemory(*this)
			ProcedureReturn #Null
		EndIf
		
	EndIf
	
EndProcedure

Procedure.i ParallelPort_Destroy( *this.PARALLEL_PORT )
	
	If *this
		
		If IsLibrary( *this\Handle )
			CloseLibrary( *this\Handle )
		EndIf
		
		FreeMemory( *this )
		*this = #Null
		ProcedureReturn *this
		
	EndIf
	
EndProcedure

;- Communication Functions

Procedure.i ParallelPort_Out( *this.PARALLEL_PORT, Bits.w = $00 )
	If *this
		*this\LastData = Bits & $FF
		ProcedureReturn CallFunction( *this\handle, "Out32", *this\Port, Bits )
	EndIf
EndProcedure

Procedure.i ParallelPort_In( *this.PARALLEL_PORT, Type.i )
	If *this
		ProcedureReturn CallFunction( *this\handle, "Inp32", *this\Port + Type )
	EndIf
EndProcedure

;- Getter Functions

Procedure.i ParallelPort_GetHandle( *this.PARALLEL_PORT )
	If *this
		ProcedureReturn *this\Handle
	EndIf
EndProcedure

Procedure.i ParallelPort_GetPort( *this.PARALLEL_PORT )
	If *this
		ProcedureReturn *this\Port
	EndIf
EndProcedure

Procedure.i ParallelPort_GetLastData( *this.PARALLEL_PORT )
	If *this
		ProcedureReturn *this\LastData
	EndIf
EndProcedure

;- Helper Functions

Procedure.i ParallelPort_Clear( *this.PARALLEL_PORT )
	If *this
		ParallelPort_Out( *this ) ; The default data parameter is $00
	EndIf
EndProcedure

And the constants include:


; Read Only Status Register.
#PARALLEL_PORT_STATUS_IRQ		= #PARALLEL_PORT_BIT2

#PARALLEL_PORT_STATUS_ERROR		= #PARALLEL_PORT_BIT3
#PARALLEL_PORT_STATUS_SELECT		= #PARALLEL_PORT_BIT4
#PARALLEL_PORT_STATUS_PAPEROUT		= #PARALLEL_PORT_BIT5
#PARALLEL_PORT_STATUS_ACK		= #PARALLEL_PORT_BIT6
#PARALLEL_PORT_STATUS_BUSY		= #PARALLEL_PORT_BIT7

; Read / Write Control Register.
#PARALLEL_PORT_CONTROL_STROBE		= #PARALLEL_PORT_BIT0
#PARALLEL_PORT_CONTROL_LINEFEED		= #PARALLEL_PORT_BIT1
#PARALLEL_PORT_CONTROL_RESET		= #PARALLEL_PORT_BIT2 ; AKA Initialize Printer OR Init.
#PARALLEL_PORT_CONTROL_SELECT		= #PARALLEL_PORT_BIT3

; These constants are icluded for completeness. All pin numbers are relative to D-Type 25, Centronics pins are between parentheses.

#PARALLEL_PORT_D0	=	#PARALLEL_PORT_BIT0			; PIN2
#PARALLEL_PORT_D1	=	#PARALLEL_PORT_BIT1			; PIN3
#PARALLEL_PORT_D2	=	#PARALLEL_PORT_BIT2			; PIN4
#PARALLEL_PORT_D3	=	#PARALLEL_PORT_BIT3			; PIN5
#PARALLEL_PORT_D4	=	#PARALLEL_PORT_BIT4			; PIN6
#PARALLEL_PORT_D5	=	#PARALLEL_PORT_BIT5			; PIN7
#PARALLEL_PORT_D6	=	#PARALLEL_PORT_BIT6			; PIN8
#PARALLEL_PORT_D7	=	#PARALLEL_PORT_BIT7			; PIN9

#PARALLEL_PORT_C0	=	#PARALLEL_PORT_CONTROL_STROBE		; PIN 1
#PARALLEL_PORT_C1	=	#PARALLEL_PORT_CONTROL_LINEFEED		; PIN 14
#PARALLEL_PORT_C2	=	#PARALLEL_PORT_CONTROL_RESET		; PIN 16	(31)
#PARALLEL_PORT_C3	=	#PARALLEL_PORT_CONTROL_SELECT		; PIN 17	(36)

#PARALLEL_PORT_S3	=	#PARALLEL_PORT_STATUS_ERROR		; PIN 15	(32)
#PARALLEL_PORT_S4	=	#PARALLEL_PORT_STATUS_SELECT		; PIN 13
#PARALLEL_PORT_S5	=	#PARALLEL_PORT_STATUS_PAPEROUT		; PIN 12
#PARALLEL_PORT_S6	=	#PARALLEL_PORT_STATUS_ACK		; PIN 10
#PARALLEL_PORT_S7	=	#PARALLEL_PORT_STATUS_BUSY		; PIN 11

; PINS 18-25 (19-30) Are all tied to GND.

The hardware:

You don’t need any special hardware other than a Centronics or similar cable and a PC with a Parallel port (I’m sure some of you keep older PCs around for a good reason!) — Aside from this if you’re planning on running the examples you might want to get some LEDs and Switches.

Something to download:

The entire sources and support files including the examples can be found Here. Remember to exit the demo programs with the ESC key so the program gets a chance to reset the output bits.

Useful companion:

During development you may want to keep an eye on the status of each pin, however not everyone has a breakout board for this particular interface so you may want to use a software version of this concept instead, one of my favourite ones is LPT.exe — It works fairly well and there are several ports to different languages in case you’re interested in modifying it to suit your own needs.

Closing up:

That’s all for now, hopefully I’ll be able to finish the project and post some of the code here. Hint: it involves controlling unipolar steppers, computer vision and webcams!

Can you guess what it is?

Cheers.