Sam Afshari's Notes - Contact me: sa at neat.lu
👀 Notes on this right here page ðŸ¤
- 2024-09-20 | Ed 2.23 is out
- 2024-01-10 | Ed - The Level Editor
- 2023-04-10 | Playing Sound Effects in Avalonia UI
- 2022-02-13 | This Is Neat-O!
- 2022-01-25 | Unity Tilemap Collision Detection
- 2021-09-14 | Talking to a Bluetooth (BLE) ELM327 Dongle
- 2021-07-29 | Talking to a Bluetooth (BLE) Pulse Oximeter - Part II
- 2021-07-04 | Talking to a Bluetooth (BLE) Pulse Oximeter
- 2021-05-17 | Virtualization and Surface Book 3
- 2021-02-20 | RedCorners.Forms Changes
- More Notes
- CameraTarget flag: Make camera move and focus on this tile*.
- TileDef list sort: Sort by Ref, Handle or default.
- Draw borders around tiles of the current board (CTRL+G to toggle)
- Duplicate Ref finder assistant: Find assets with the same Ref and quickly rename them to unique values
- Fix bugs related to Rule Brush, Folder and TileDef management
- Fix undo drawing making the camera jump to 0,0.^
- Make undo drawing faster.^
- Make zooming in and out with scroll wheel smoother.
- Zoom and move the camera to cursor.
- Circle brush with size 3 is + instead of a square.
- Fix issues with animations and optimize drawing performance.
- Announcer UI and chimes
- IsPlayer TileDef flag
- Performance improvement: Don’t run polish on tiles that are being drawn
- Refactor renderer
- Pan camera with space bar
- CTRL+D to deselect
- Export animations to Unity and play them*
- Export collisions to Unity*
- Flag to clone TileDef per tile on runtime or use static (shared) data
- New animation code in Editor and Unity*
- CTRL+S to save
- Annotation TileDef flag: Ignore exporting/spawning sprites in game*
- Unity tile Become()*
- Unity tile Mimic()*
- Tile-level collision inheritance*
- Board-level collision override*
- Draw colliders*
- Duplicating assets assigns unique Refs
- Gravity multiplier*
- Rotation and position locks*
- Physics simulation mode per TileDef (with export to Unity RigidBody2D)*
- Propagate colliders to all TileDefs of a Rule Brush
- RPM is
01 0C\r
- Speed is
01 0D\r
- Throttle position is
01 11\r
- and so on.
- For Reading:
0734594a-a8e7-4b1a-a6b1-cd5243059a57
- For Writing:
8b00ace7-eb0b-49b0-bbe9-9aee0a26e1a3
- Command:
0x03
- Block:
0
- File Name:
filename\0
- Command:
0x04
- Block:
0..i..n
TitledContentView
toTitledGroup
TabbedContentView
toTabGroup
HiddenEntryView
toHiddenEntry
TitleViewTemplate
: assigns the control template ofTitleView
.BodyTemplate
: assigns the control template of the body (Content
).TitleBarTemplate
: assigns the control templates of the title bar.
Ed 2.23 is out - Fri, Sep 20, 2024
Ed 2.23 is out on Steam. These are the new features and changelog for this build. I started writing changes on Post-its and I plan to collect them for every release to compile a changelog. Old school methods seem faster than loading Trello/Jira’s JavaScript!
Changelog
(*Unity Experimental)
(^Known issues exist when undoing draws)
KiloTexture - OptimizedWall
Unity integration is coming along, with a focus on making a 2D platformer game mode work. I added a specific TileDef flag named OptimizedWall, which separates colliders from sprites, batches sprites into 2048x2048 pixels (or smaller) textures and draws those bigger textures instead of spawning small tiles individually. I’m tempted to call it KiloTexture as an homage to idTech’s MegaTexture.
The colliders are run through a merging algorithm that returns polygons of the union of rect colliders, and those polygons are spawned as Polygon Collider 2Ds in Unity.
Animated tiles are excluded from this process and are rendered separately.
Unity Export
Another challenge is to find the most optimal way to store data for Unity. Currently I’m writing data as code, because it’s fast at runtime, and can be accessed in any way they want by the programmer, git friendly, and readable. However, Unity Editor tends to re-compile scripts every time they change, and these large source files make the development and debug cycle slow, so I might move data out to resource files.
This is how large the main data source file is.
On another note, spawning a medium-sized level at edit times and saving the Unity scene file makes the scene file as large as 500 MB or more, and that already categorizes the file as LFS by Github. What’s the point of making things text-based if they aren’t properly handled by Git? So I think I should rethink how I’m serializing data in general.
Games
The main reason I’m focused on Unity integration and specifically on making the 2D platformer thing work is, if I can reduce the development to release cycle of an okay 2D platformer down to a month or so, Ed can be used at game jams to make platformers, and meanwhile I can bring artists in to create a game per month, early 90s style. We’ll see how it goes.
Ed - The Level Editor - Wed, Jan 10, 2024
.
I’ve been working on a level editor for tile based games for quite some time now. Initially, it started as a tool to quickly design level for my Toy Box Jam submission, as I already had the gameplay code in place and needed to make some levels and swap sprites.
It’s now a polished tool, available for Windows, macOS and iOS, which you can use anywhere you want to design your games.
Here’s a list of features:
Rule-based brushes
Set up rule-based brushes for terrains, platforms and other features by assigning rules to sprites, so the appropriate sprites are automatically chosen depending on their neighbors. Built-in support for bitmasking, 47-tiles and 4x4 tiles terrains.
Tile definition classes
Set up tile definitions with various animation settings, background and tint colors and override their sizes and offsets on the grid. Additionally, you can assign variables and values to them and write custom scripts for tile definitions.
Sprite management
Import and slice your sprite sheets, remove opaque backgrounds by specifying a key color and set up tile bitmasks and brushes right within the sprite sheet editor and export them to rule brushes.
Auto terrain
Automatically generate an entire 47-tile terrain set from a single sprite. Adjust corner radiuses individually, and optionally stamp decal sprites on different sides. Export generated terrains as PNG and further edit them in your image editing programs.
Auto brush
White box your levels and puzzles with generic tiles and define auto brush regions that automatically transform them into high quality environments. Swap environments instantly without having to redraw levels.
Multi-layer level design
Create multiple boards per level and benefit from onion tools to draw on different layers with ease. Export levels as PNGs or ASCII-based scripts. Use Quads to add non-grid based 2D entities to your levels.
Fully-customizable boards
Adjust the grid size of boards individually, as well as modifying the horizontal and vertical gaps, background colors, alpha blending modes and tint colors. Each object in a level has its own parallax settings to enable parallax scrolling effects.
Create and draw patterns
Draw repetitive areas by creating patterns from a selected set of tiles. Stamp them with precision, or use the rectangle or ellipse fill tool to paint the pattern in a repetitive style on a designated area. Patterns can be created from any board and drawn on different boards or even other levels.
Color palettes and Pixel art
Import color palettes, create your own, and draw solid colors on grids. Create your pixel art directly in Ed, export them as a linked-sprite sheet back to the sprite sheet editor and slice them into sprites, redrawing them on your game levels. End-to-end, from pixel art into games, can be achieved without ever leaving Ed.
Design anytime, anywhere
Ed is available on your desktop, tablet and even iPhone. Open your Ed files on your mobile device and design your game on the go. Cloud sync and team accounts coming soon!
Download
You can get Ed on the following platforms:
Playing Sound Effects in Avalonia UI - Mon, Apr 10, 2023
If you’re looking for a way to develop cross-platform desktop-oriented applications, Avalonia UI might just be the framework for you. However, the documentation and third-party libraries can still be a bit immature. In this post, I’ll be sharing my experience developing an application that required playing audio files on different platforms, and how I managed to get it to work.
Goal
Our goal is to play audio files from a local file or a URL. To achieve this, the cross-platform code calls a function pointer that is defined separately on each platform as Func<string, Task>
, where the input is the path/URL to the audio file. You can set this up with interfaces and dependency injection, but I chose to keep it old school.
Windows
Avalonia’s default template comes with one single Desktop project. However, to make platform-specific calls, we’ll need to fork that into two separate projects for Windows and macOS. To get started with Windows, change the TargetFramework
of your Windows project to net7.0-windows10.0.17763.0
. Note that you can’t target Windows 7, and at a minimum, you’ll need to target Windows 10 to get access to the APIs we’ll be using. Your csproj should look like this:
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net7.0-windows10.0.17763.0</TargetFramework>
<Nullable>enable</Nullable>
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
</PropertyGroup>
Once you’ve made this change and reloaded your project, you’ll gain access to the Windows.Media
namespaces, which allow you to easily play media files using the Windows.Media.Playback.MediaPlayer
class:
var player = new MediaPlayer();
player.Source = MediaSource.CreateFromUri(new Uri("file://c:/media.m4a"));
player.Play();
MediaSource
supports loading local files using file://
Uris or remote files.
macOS
On macOS, we can use the afplay
command-line utility to play audio files. To do this, we can simply write a function that runs a new process for afplay [path]
to play the sound effect we want:
new Process()
{
StartInfo = new ProcessStartInfo
{
FileName = "/bin/bash",
Arguments = $"-c \"afplay 'media.mp4'\"",
RedirectStandardOutput = true,
RedirectStandardInput = true,
UseShellExecute = false,
CreateNoWindow = true,
}
}.Start();
This is exactly what the NetCoreAudio project does for its macOS implementation and in general on Unix.
If you want to download a remote file, you can use System.Net.Http.HttpClient
to do that:
using var client = new HttpClient();
var bytes = await client.GetByteArrayAsync(url);
File.WriteAllBytes(localPath, bytes);
WebAssembly
Playing audio on the web can be done using an Audio
object in JavaScript and calling the play()
method on it. To call JavaScript functions from your C# code, you can use the JSImport
attribute.
First, define a function in main.js
that plays an audio file, for example:
globalThis.playSound = function (url) {
var audio = new Audio(url);
audio.play();
}
Then you can JSImport
this as a C# method anywhere you want like this:
using System.Runtime.InteropServices.JavaScript;
...
[JSImport("globalThis.playSound")]
public static partial void PlaySound(string url);
Finally, call the PlaySound
method in C# to run the globalThis.playSound
JavaScript function:
PlaySound("http://sound.com/audio.mp4");
However, when dealing with a website, you might run into CORS (Cross-Origin Resource Sharing) issues. Make sure the remote host allows you to download the file you want. It’s always a good idea to look at your browser’s DevTools console for hints about any issues related to cross-site scripting errors.
This Is Neat-O! - Sun, Feb 13, 2022
Check out my submission for Toy Box Jam 3, This Is Neat-O!
Thirty years ago, Captain Neat-O lost his way home after entering a doomed trans-dimensional portal somewhere around Mars.
It’s up to you to help him find his way back home, before his parents find out…
Easy Mode: Collect all Neat Coins in each level to open the exit portal. Go to the portal to get to the next level.
Hard Mode: Collect all pickups in each level and then finish the level. It turns out Captain Neat-O doesn’t mind vegetables, but hates CHICKEN!
If you don’t feel like finishing the levels or get stuck, feel free to skip levels by pressing +. You can even skip to the end and see what happens. I don’t mind :)
Unity Tilemap Collision Detection - Tue, Jan 25, 2022
While working on a 2D platformer on Unity, I decided to implement ladders with tile maps with a specific layer designated for ladders. I added a Tilemap Collider 2D component to it with Is Trigger set to true
. The plan was to detect the overlap of player and a ladder tile using Unity’s OnTriggerEnter2D(Collider2D)
and OnTriggerExit2D(Collider2D)
methods.
The Collider2D
object refer to the collider attached to the tilemap. I thought collider2D.transform
or .bounds
properties would return the position of the actual overlapping tile, but I was wrong.
In the end I solved the problem using a different approach:
1, Get the Tilemap
object for the ladder,
2, Use the .WorldToCell(Vector3)
method of the tilemap to get the discrete cell position of the tile that overlaps with the passed position, in this case player’s transform.position
.
3, The center of the overlapping tile would be the world position of the tile map + the cell position + half of tileMap.cellSize
.
_
foreach (var collision in Colliders.Where(x => x.gameObject.layer == LadderLayerId))
{
IsLadder = true;
var tileMap = collision.GetComponent<Tilemap>();
var cellPos = tileMap.WorldToCell(transform.position);
var tile = tileMap.GetTile(cellPos);
if (tile != null)
LadderCenter = tileMap.transform.position + cellPos + tileMap.cellSize * 0.5f;
}
Talking to a Bluetooth (BLE) ELM327 Dongle - Tue, Sep 14, 2021
I have an ELM327 OBD2 BLE dongle that shows up as IOS-Vlink
. To communicate with it, the service ID is: E7810A71-73AE-499D-8C15-FAA9AEF0C3F2
and both read and write is done using the characteristic BEF8D6C9-9C21-4C9E-B632-BD58C1009F9F
.
Once the car (ECU) is on and the Bluetooth is connected, we need to initialize the dongle, by sending:
AT E0\r
AT L0\r
AT SP 00\r
01 00\r
AT E0
is to turn echo off. AT SP 00
searches for the right protocol to use to communicate with the ECU.
Once initialized, we can run a loop to query for the values we want:
This Wikipedia article has a table of PIDs that can be queried from the car and how to translate the results to human readable values.
Generally when a PID is queried (e.g. 01 0C\r
), the result is something like 41 0C 0B C0
where 0C
is the PID for this response and 0B C0
are the actual returned values in hex.
I often get corrupt replies from the dongle such as 41 0C 0B C
, where the message is not fully received, which I ignore.
Responses end with >
, so that’s something to look for. Read until you get >
, split by line breaks, parse the lines.
Some PIDs take longer to get a response for than the others, so make sure you query what you want, so you can get the desired values with the highest frequency. Also note that ECUs have different speeds, some return results faster, some slower, some need waits between commands.
Talking to a Bluetooth (BLE) Pulse Oximeter - Part II - Thu, Jul 29, 2021
These oximeters also continuously record oxygen, heart rate, motion and other values in their internal memory as files. Files are stored in a binary format that can be decoded as described in this note.
The first 40 bytes are the header:
00 int16 version (2 bytes)
02 int16 year
04 byte month
05 byte day
06 byte hour
07 byte minute
08 byte second
09 int16 file size
13 int16 duration in seconds
17 byte average O2
18 byte minimum O2
19 byte 3pct O2
20 byte 4pct O2
22 int16 O2 < 90% seconds
24 byte events under 90%
25 byte score
Take the total length of the file (number of bytes), remove 40 (i.e. the length of the header). Divide by 5 (i.e. the length of a record). You’ll get the total number of records in the file.
You can get the interval between each record by dividing the duration (bytes 13 and 14 of the header) by the number of records.
Reading Records
Skip 40 bytes (the header), you’ll arrive at the beginning of the first record. Take 5 bytes:
00 O2 %
01 Heart Rate bpm
02 ??
03 Motion
04 Vibration
As you already have the interval, you can estimate each record’s timestamp by multiplying record ID by interval, plus the start time (bytes 02 to 08 inclusive of the header).
Talking to a Bluetooth (BLE) Pulse Oximeter - Sun, Jul 4, 2021
I was playing around with a Viatom SleepU Pulse Oximeter the past few days. It’s a device with a ring-shaped sensor that you wear on your finger and it monitors and continuously records your blood oxygen percentage and heart rate.
To communicate with this device over BLE, you need to look for the service with UUID 14839ac4-7d7e-415c-9a42-167340cf2339
. This service has two characteristics that interest us:
We write to the second characteristic and monitor the value update of the first characteristic for reading.
In this note I explain how to read device information, sensor values and files from the device.
But first, let’s discuss packet formats.
Write Packets
To send a message to the device, you have to create a packet with the following structure (byte array):
00 byte 0xAA
01 byte requested_command
02 byte requested_command XOR 0xFF
03 ushort (2B) file_block_id [when reading a file. set to 0 otherwise.]
05 ushort (2B) payload_length [when sending data. set to 0 otherwise.]
07 byte_array payload [optional]. This can be the name of a file to download for example. Use UTF-8 to convert text to byte array.
07+payload_length byte CRC of bytes [00 to 07)
To calculate the CRC, use the following algorithm:
static byte CRC(IEnumerable<byte> bytes)
{
byte crc = 0;
foreach (var b in bytes)
{
var chk = (byte)(crc ^ b);
crc = 0;
if ((chk & 0x01) != 0) crc = 0x07;
if ((chk & 0x02) != 0) crc ^= 0x0e;
if ((chk & 0x04) != 0) crc ^= 0x1c;
if ((chk & 0x08) != 0) crc ^= 0x38;
if ((chk & 0x10) != 0) crc ^= 0x70;
if ((chk & 0x20) != 0) crc ^= 0xe0;
if ((chk & 0x40) != 0) crc ^= 0xc7;
if ((chk & 0x80) != 0) crc ^= 0x89;
}
return crc;
}
There is a maximum message length limit of, I guess, 20 bytes. You can send your message in chunks if it’s larger than that:
async Task WriteAsync(byte[] bytes)
{
if (bytes == null) return;
while (bytes.Length > 0)
{
var chunk = bytes.Take(20).ToArray();
await WriteAsyncFunc(chunk);
bytes = bytes.Skip(20).ToArray();
}
}
If you are using later versions of C#, you can optimize this code and not duplicate the array in every loop.
Read Packets
Incoming packets come in the following format. Note that a message can come in multiple packets and therefore we have to keep track of how many bytes we expect, so we can join subsequent packets that carry the same message together.
00 byte device ID, must be 0x55
01 byte
02 byte. [01] must be equal to 0xFF XOR [02]
05 ushort (2B) + 8 = total bytes to expect
Keep reading until you have all the bytes you expect. Once you have enough bytes, take the last byte, that should be the CRC of everything except the last byte.
Calculate the CRC of everything except the last byte and make sure it is equal to this value.
Commands
0x14: Device Information
To request device information, send a packet with the command 0x14
. Your bytes in hex should look like this: aa14eb00000000c6
.
The response will be something like this:
5500ff000000027b22526567696f6e223a224345222c224d6f6
4656c223a2231363534222c224861726477617265566572223a224
141222c22536f667477617265566572223a22312e322e30222c224
26f6f746c6f61646572566572223a22302e312e302e30222c22466
96c65566572223a2233222c2253504350566572223a22312e34222
c22534e223a2232303131324232363237222c2243757254494d452
23a22323032312d30372d30332c31363a33373a3133222c2243757
2424154223a22363325222c224375724261745374617465223a223
0222c224375724f7869546872223a223837222c224375724d6f746
f72223a22313030222c22437572506564746172223a22393939393
9222c224375724d6f6465223a2230222c224375725374617465223
a2232222c224272616e6368436f6465223a2232313037303030302
22c2246696c654c697374223a22323032313037303331343035333
62c32303231303730333134343832312c323032313037303330313
13233352c227d00000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000
0000000000000007c
Looking closely at the hex, you can see the 7c
in the end is the CRC. Ignoring that, you have an almost 512 bytes long message that ends at some point and is padded with 0
s. The first few bytes in the beginning (5500ff00000002
) are packet details.
The rest of the bytes (7b
to 7d
) contain a JSON string that has the device information.
0x17: Sensors
Send a packet with command 0x17
(aa17e8000000001b
) and you will receive something like this:
5500ff00000d00615400000000004b000000000058
As explained above, the actual payload is this part:
615400000000004b0000000000
Data structure:
00: O2 level
01: Heart Rate (bpm)
07: Battery %
0x03: Open File
To download a file, you have to send a request to open it, a few requests to read it and a final request to close.
Send a request of:
To open a file. The response’s first four bytes (uint) indicate the total size of the requested file in bytes. Remember this number.
0x04: Read File
You download the file in blocks (chunks). Send a request of:
To download the i-th block. Every time you receive a message, subtract the size of the message (not counting the header and CRC bytes) from the total expected bytes (obtained from the Open phase). Increase the block
number by one every time and repeat the read request until you have all the bytes you need.
Save them to a file.
0x05: Close File
Send a request with command 0x05
to close the file.
Virtualization and Surface Book 3 - Mon, May 17, 2021
I recently bought a Surface Book 3 and installed a VMWare virtual machine on it. It was running super slow. Some Googling around lead me to this discussion, and the solution worked for me. Leaving it here for future use.
1. Turn off Hyper-V. Run the "Turn Windows features on or off" applet and uncheck the entire "Hyper-V" tree
2. Disable Credential Guard: Run the "Edit group policy" applet, and navigate to the Local Computer Policy > Computer Configuration > Administrative Templates > System > Device Guard group. For the "Turn On Virtualization Based Security", set it to "Disabled"
3. Turn off hypervisor in the boot loader: in PowerShell as Administrator, type
bcdedit /set hypervisorlaunchtype off
4. Disable DeviceGuard: run the "Registry Editor" applet and navigate to Computer > HKEY_LOCAL_MACHINE > SYSTEM > CurrentControlSet > Control > DeviceGuard group. set the "EnableVirtualizationBasedSecurity" to 0, set "RequireMicrosoftSignedBootChain" to 0. Then navigate further to ... Scenarios > HyperVisorEnforcedCodeIntegrity and set "Enabled" to 0
5. Disable Memory Integrity: in the Settings Applet, navigate to Update & Security > Windows Security > Device Security > Core Isolation. Turn the Memory Integrity option "Off"
When you reboot, you should have "Virtualization Based Security: not enabled" and the Intel utility will show VT-x enabled.
RedCorners.Forms Changes - Sat, Feb 20, 2021
The following classes are renamed in RedCorners.Forms:
Some unnecessary TwoWay
bindings in TitledGroup
, TitleBar
and TabGroup
have been changed to OneWay
.
Demos are updated.
Android SDK version is changed to 10
from 9
.
The following control templates are added to TitledGroup
:
- 2021-02-20 | RedCorners.Forms.GoogleMaps Breaking Changes
- 2021-02-17 | Notes on Uno Platform
- 2021-02-08 | POIWorld Windows App
- 2021-02-07 | World Time Lookup
- 2021-02-06 | Replicate
- 2019-09-01 | Creating Icon Sets for Xamarin.Forms
- 2019-08-23 | Xamarin.Forms and Notch
- 2019-08-18 | Customizing Xamarin.Forms Frame Shadow
- 2019-04-28 | Read and Write GPS coordinates with RedCorners.ExifLibrary
- 2019-02-22 | Lines in Unity
- 2018-11-27 | USB devices won’t show up on VMware’s list
- 2018-08-26 | RestSharp returns 0 for custom ASP.NET Core middleware response
- 2018-07-23 | Change Image Format in C#
- 2018-07-23 | Images captured by iOS show up rotated on Android
- 2018-06-07 | Checking whether a DLL is 32-bit or 64-bit
- 2018-05-30 | mpc.exe outputs an empty Resolver
- 2018-05-29 | Resetting Windows 10 bash user password
- 2018-05-27 | Solve "The "User7ZipPath" parameter is not supported"
- 2018-05-27 | Solving "Native linking failed" issues running Xamarin.iOS on Simulator
- 2017-05-11 | EF / SQL Server writes too slow?
- 2016-08-20 | Xamarin.Android Rounded Corners Masked Layout
- 2016-07-08 | REST requests with Xamarin and RestSharp
- 2016-06-24 | Tips and Tricks on Using SQLite-Net with Xamarin.iOS
- 2016-02-24 | Batch resizing images with Python and Pillow
- 2016-02-16 | Traces of Love Random Development Notes
- 2016-02-13 | Exporting Unity frames as Animated GIFs
- 2015-09-24 | Accessing Vimeo and YouTube APIs with Xamarin.iOS
- 2015-09-24 | First wave of Uptred products released!
- 2015-07-01 | Mono Frustrations: "The authentication or decryption has failed."
- 2015-07-01 | Mono Frustrations: JSON Deserializer and Booleans
- 2015-07-01 | Mono Frustrations: WebRequest
- 2015-02-15 | Collaborative Whiteboard Tutorial, Part One
- 2015-02-15 | Collaborative Whiteboard Tutorial, Part Two
- 2014-12-23 | Relocating Outlook Data Files
- 2014-12-17 | Magnetic Interaction with Mobile Games
- 2014-08-19 | VimeoDotNet 3 on GitHub
- 2014-08-05 | MELODIE is available for iOS and Android!
- 2014-07-31 | Conversion to Dalvik error while Exporting APK
- 2014-07-10 | Game of Drones Released!
- 2014-07-06 | Gotchas: Using Cocos2d-x libExtensions and libNetwork
- 2014-07-04 | Gotchas: Post shader effects in Cocos2d-x
- 2014-07-04 | Gotchas: Repeating textures in Cocos2d-x
- 2014-06-21 | Neat Bundle Released!
- 2014-06-20 | Gotchas! Shaders in Cocos2d-x
- 2013-10-01 | New titles published on Google Play!
- 2013-09-06 | Fixing Cocos2D-x exe crash
- 2013-07-20 | Fixing Doom3 BFG Edition on multi-display setups
- 2012-07-23 | Improved Auto-complete in Neat Console
- 2012-07-01 | VimeoDotNet, available now for Metro!
- 2012-06-19 | Available Now: Vimeo for Windows Advanced Uploader
- 2012-06-15 | VimeoDotNet Updated
- 2012-05-29 | Introducing Kintouch
- 2011-12-23 | Speech and Skeletal Tracking in River Raid X
- 2011-12-06 | Kinect SDK and XNA
- 2011-11-23 | Kinectoid
- 2011-11-22 | Integrating Kinect into Neat Game Engine
- 2011-11-16 | New Releases
- 2011-08-20 | VimeoDotNet just got cooler.
- 2011-06-30 | Loading Transparent PNGs in OpenGL for Dummies!
- 2011-05-05 | Download Vimeo for Windows
- 2011-04-23 | Vimeo Upload API
- 2011-04-12 | Vimeo for Windows 2.0 Update
- 2011-03-28 | Vimeo API
- 2011-03-07 | Sectors World Designer
- 2011-01-29 | Neat Update
- 2010-12-14 | Stand Alone Neat Console
- 2010-12-10 | Loops in Neat Script
- 2010-11-22 | River Raid X
- 2010-11-18 | This is Neat!
- 2010-11-02 | Separating Axis Theorem (SAT)