<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0"><channel><title>mahnke.tech</title><link>http://www.mahnke.tech</link><description /><language>en</language><copyright>2018-2022, mahnke.tech</copyright><item><title>3d Graphics on the Commodore 64, Part One</title><link>http://www.mahnke.tech/blog/2019-04-12-3d-graphics-on-the-commodore-64-part-one.html</link><description>

&lt;p&gt;&lt;em&gt;Published on 2019-04-12&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This is something that came from an exercise I’ve given myself to improve my
assembly language skills, which in turn is to improve &lt;a class="reference external" href="2019-04-12-the-vale8-instruction-set.html"&gt;improve the ISA design
for my homebrew vale8 computer&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I’m interested in &lt;a class="reference external" href="https://www.youtube.com/watch?v=5MexnBunH_g"&gt;demoscene culture&lt;/a&gt; in general, and there’s a lot
of &lt;a class="reference external" href="http://www.antimon.org/code/Linus/"&gt;demoscene-related&lt;/a&gt; &lt;a class="reference external" href="http://codebase64.org/doku.php?id=base:demo_programming"&gt;documentation&lt;/a&gt; for the C64
machine. After doing a custom font and basic scroller effects on the C64, I
thought a more challenging project in 6502 might be to animate wireframe
geometry (the seminal “spinning cube” effect).&lt;/p&gt;
&lt;p&gt;Here’s the result, a spinning pyramid.&lt;/p&gt;
&lt;video width="640" height="480" controls=""&gt;&lt;source src="../_static/c64-3d-graphics-series/test_pyramid.mp4" type="video/mp4"/&gt;&lt;/video&gt;&lt;p&gt;In this multi-part post series, we’ll make this effect using C and 6502
assembly. The line drawing routines are in 6502 assembly, whereas the
model’s vertices are pre-calculated using a C program.&lt;/p&gt;
&lt;section id="prerequisites"&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;Understanding of C.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Understanding of 6502 assembly language.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Ability to assemble programs and run them in an &lt;a class="reference external" href="http://vice-emu.sourceforge.net/"&gt;emulator&lt;/a&gt;, or on a C64.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id="further-references"&gt;
&lt;h2&gt;Further References&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://en.wikibooks.org/wiki/6502_Assembly"&gt;6502 Assembly&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="http://sta.c64.org/cbm64mem.html"&gt;Commodore 64 memory map&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="reference external" href="https://archive.org/details/c64-programmer-ref"&gt;Commodore 64 Programmer’s Reference Guide&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id="disclaimer"&gt;
&lt;h2&gt;Disclaimer&lt;/h2&gt;
&lt;p&gt;I’m a novice 6502 programmer. Demoscene veterans do this sort of thing with
much better performance. I’m just showing the way that I worked out for myself.
I know there are opportunities for optimization, and I’m looking forward to
learning more of them.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="procedure"&gt;
&lt;h2&gt;Procedure&lt;/h2&gt;
&lt;p&gt;We can divide the procedure of animating 3d geometry into a few steps. The
program must follow each step for each frame of animation.&lt;/p&gt;
&lt;section id="draw-the-model-s-faces"&gt;
&lt;h3&gt;Draw the Model’s Faces&lt;/h3&gt;
&lt;p&gt;For each face, draw a line from one vertex of the face to the next, in a
counterclockwise direction.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="transform-the-3d-model-in-the-world"&gt;
&lt;h3&gt;Transform the 3d Model in the World&lt;/h3&gt;
&lt;p&gt;In our case, change its rotation about the y axis each frame.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="transform-model-vertices-to-display-coordinates"&gt;
&lt;h3&gt;Transform Model Vertices to Display Coordinates&lt;/h3&gt;
&lt;p&gt;Convert each vertex from its 3d coordinate space to
a 2d pixel coordinate on the C64’s 320x200 bitmap display.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="prerequisites-to-drawing-lines"&gt;
&lt;h2&gt;Prerequisites to Drawing Lines&lt;/h2&gt;
&lt;p&gt;Modern video cards support graphics APIs that are high enough in level as to
provide either &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Immediate_mode_(computer_graphics)"&gt;immediate-&lt;/a&gt; or
&lt;a class="reference external" href="https://en.wikipedia.org/wiki/Retained_mode"&gt;retained-mode&lt;/a&gt; functions to
draw primitives like lines and polygons. The C64 provides no such interface for
drawing primitives in its bitmap modes. Instead, we set the color of each pixel
individually. Since we’ll implement line drawing routines that will tell us which pixels
to set, we need to also make some routines to actually set those
pixels.&lt;/p&gt;
&lt;p&gt;We’ll understand how to use
the C64’s standard high-resolution bitmap mode and then create some subroutines
to make it convenient to use with cartesian coordinates.&lt;/p&gt;
&lt;section id="standard-high-resolution-bitmap-mode"&gt;
&lt;h3&gt;Standard High-resolution Bitmap Mode&lt;/h3&gt;
&lt;p&gt;The C64 provides two bitmap modes. The one we will use is the standard
high-resolution bitmap mode. This mode gives us 320x200 pixels, where each
pixel may be one of 2 colors chosen from the &lt;a class="reference external" href="https://www.c64-wiki.com/wiki/Color"&gt;16-color palette&lt;/a&gt;. I’ll refer to it as “bitmap mode”
going forward.&lt;/p&gt;
&lt;section id="enabling-bitmap-mode"&gt;
&lt;h4&gt;Enabling Bitmap Mode&lt;/h4&gt;
&lt;p&gt;To enter bitmap mode, set bit 5 of register $d011 to 1, as follows:&lt;/p&gt;
&lt;div class="highlight-none notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span/&gt;    lda $d011
    ora #$20
    sta $d011
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="setting-bitmap-memory-location"&gt;
&lt;h4&gt;Setting Bitmap Memory Location&lt;/h4&gt;
&lt;p&gt;The location of the start of bitmap memory can be either $0000 or $2000 (8192).
This number is in bytes &lt;em&gt;relative&lt;/em&gt; to the start of the current VIC bank. The
default VIC bank starts at memory location $0000. If we leave it there, we
must set the start of bitmap memory to $2000 since there are some lower memory
values we cannot modify.&lt;/p&gt;
&lt;p&gt;To set the start of bitmap memory to $2000, set bit 3 of register $d018
to 1:&lt;/p&gt;
&lt;div class="highlight-none notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span/&gt;    lda $d018
    ora #$08
    sta $d018
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="bitmap-memory-arrangement"&gt;
&lt;h4&gt;Bitmap Memory Arrangement&lt;/h4&gt;
&lt;p&gt;The bitmap memory is an 8192-byte array of memory. Each bit of each memory
address is used to set the color of a corresponding pixel on the display.&lt;/p&gt;
&lt;p&gt;From the perspective of a human accustomed to using the cartesian coordinate
system, the VIC uses bitmap memory in an inconvenient way. We might have
expected the memory to be mapped to the display something like this.&lt;/p&gt;
&lt;img alt="../_images/bitmap_mem_ideal.svg" src="../_images/bitmap_mem_ideal.svg"/&gt;&lt;p&gt;Instead, we have this.&lt;/p&gt;
&lt;img alt="../_images/bitmap_mem_real.svg" src="../_images/bitmap_mem_real.svg"/&gt;&lt;p&gt;One way to think of the bitmap memory is a 40x25 grid of cells, each of which
is 8 pixels wide and 8 pixels high. This gives us 320 columns and 200 rows of
pixels.&lt;/p&gt;
&lt;p&gt;The grid of cells starts in the top left corner of the display. The bitmap
memory address corresponds to a row of 8 pixels in a cell. When we increment
the bitmap memory address, we move down to the next row of pixels in the
current cell. When we move past the bottom row of pixels in the cell, we move
to the top row of pixels in the next cell to the right. When we move past the
rightmost cell in the row of cells, we move down to the leftmost cell in the
next row of cells.&lt;/p&gt;
&lt;p&gt;Once again, the value of each bitmap memory address controls the colors of one
row of 8 pixels in a cell. Bit 7 (the highest bit) of the value controls the
leftmost pixel, and bit 0 (the lowest bit) controls the rightmost pixel. Since
each bit can be set to either 0 or 1, there are two possible colors for each
pixel in any given cell.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="bitmap-colors"&gt;
&lt;h4&gt;Bitmap Colors&lt;/h4&gt;
&lt;p&gt;In bitmap mode, each byte of display memory $0400-$07e7 controls the color of
all pixels in a corresponding 8x8 cell of the bitmap. The upper 4 bits of the
byte determine the color of a pixel whose bit is 1 in bitmap memory, and the
lower 4 bits of the byte determine the color of a pixel whose bit is 0 in
bitmap memory. The display memory maps to bitmap cells left to right, top to
bottom. The following example sets the second cell in the first row of cells
(pixel rows 0-7 and columns 8-15) to an alternating cyan-and-black pattern, as
shown in the previous images.&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span/&gt;lda #$aa
sta $2008
lda #$30
sta $0401
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Here is a &lt;a class="reference external" href="../_static/c64-3d-graphics-series/test_bitmap.asm"&gt;test program&lt;/a&gt; demonstrating
how bitmap and color memory work.&lt;/p&gt;
&lt;img alt="../_images/test_bitmap.png" src="../_images/test_bitmap.png"/&gt;
&lt;p&gt;This is everything we need to know about bitmap mode before we implement our
drawing routines.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="pixel-placement-routines"&gt;
&lt;h3&gt;Pixel Placement Routines&lt;/h3&gt;
&lt;p&gt;Our line drawing algorithms will give us the results in cartesian coordinates.
This is typical, so we want to address the bitmap in cartesian terms, if
possible. So let’s define some drawing routines that take cartesian coordinates
as input and modify the bitmap memory appropriately behind the scenes.&lt;/p&gt;
&lt;p&gt;We’ll define several routines that allow us to control a “pen” on the display.
With these routines, we can move the pen to (almost) any (x, y) coordinate on
the display, move the pen relative distances in four directions, and set the
color of the pixel where the pen is located. Here is the commented source
code for all the functions.&lt;/p&gt;
&lt;div class="highlight-none notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span/&gt;;; pen_init: Initialize the pen. Call this routine before
;; each invocation of pen_move_to.
pen_init:
    ;; Set pen address to beginning of
    ;; bitmap memory.
    lda #$20
    sta pen_addr_hi
    lda #$00
    sta pen_addr_lo

    ;; First pixel row in the cell.
    lda #$07
    sta pen_row_loc

    ;; First pixel column in the cell.
    lda #$80
    sta pen_pixel_bit

    rts
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="highlight-none notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span/&gt;;; pen_move_to: Move the drawing pen to an (x, y) pixel
;; coordinate position on the display.
;; args
;;   y: y coordinate of the position
;;   x: x coordinate of the position
pen_move_to:
    pha
    tsx

    ;; Divide y by 8 and look up the address of the cell in
    ;; bitmap memory. The result is within 7 bytes of the
    ;; right address for the y coordinate. Store the result
    ;; to pen position.
    lda arg0
    lsr
    lsr
    lsr
    tax
    lda .cell_addr_hi,x
    sta pen_addr_hi
    lda .cell_addr_lo,x
    sta pen_addr_lo

    ;; Take y % 8, which is the number of bytes to add to
    ;; get the pixel row. Add it to the current pen
    ;; position and store new pen position.
    ; y % 8 == a &amp;amp; (8 - 1)
    lda arg0
    and #$07
    sta $0101,x

    clc
    adc pen_addr_lo
    sta pen_addr_lo

    ;; pen_row_loc == 7 - pixel row
    lda #$07
    sec
    sbc $0101,x
    sta pen_row_loc
    pla

    ;; Begin with pen_pixel_bit == #$80, which
    ;; represents the leftmost pixel column of the current
    ;; cell. Shift right x number of times. If we shift all
    ;; the way to the right and out of the register, add 8
    ;; to disp_pen_addr, which moves to the next cell.
+++ ldx arg1
    beq ++
-   lda pen_pixel_bit
    lsr
    sta pen_pixel_bit
    bne +
    lda #$80
    sta pen_pixel_bit
    lda #$08
    clc
    adc pen_addr_lo
    sta pen_addr_lo
    bcc +
    inc pen_addr_hi
+   dex
    bne -
++  rts
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="highlight-none notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span/&gt;;; pen_move_up: Move the pen one pixel row up on the
;; display.
pen_move_up:
    ;; Move one pixel row up in the current cell.
    inc pen_row_loc
    lda #$08
    sec
    sbc pen_row_loc
    bne ++
    ;; If we leave the current cell, move to the bottommost
    ;; pixel row one cell up; effectively subtract 313 from
    ;; the pen address.
    lda #$00
    sta pen_row_loc
    lda #$01
    clc
    adc pen_addr_lo
    sta pen_addr_lo
    bcs +
    dec pen_addr_hi
+   lda #$c6
    clc
    adc pen_addr_lo
    sta pen_addr_lo
    bcs +
    dec pen_addr_hi
+   rts
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="highlight-none notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span/&gt;;; pen_move_down: Move the pen one pixel row down on the
;; display.
pen_move_down:
    ;; Move one pixel row down in the current cell.
    dec pen_row_loc
    bpl ++
    ;; If we leave the current cell, move to the topmost
    ;; pixel row one cell down; add 313 to the pen address.
    lda #$07
    sta pen_row_loc
    lda #$ff
    clc
    adc pen_addr_lo
    sta pen_addr_lo
    bcc +
    inc pen_addr_hi
+   lda #$3a
    clc
    adc pen_addr_lo
    sta pen_addr_lo
    bcc +
    inc pen_addr_hi
+   rts
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="highlight-none notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span/&gt;;; pen_move_left: Move the pen one pixel row left on the
;; display.
pen_move_left:
    ;; Shift the pixel column bit left and store.
    lda pen_pixel_bit
    clc
    asl
    sta pen_pixel_bit
    bcc +
    ;; If we shifted out of the left, put the bit back into
    ;; the right side of the value, and move to the same
    ;; pixel row in the previous cell; effectively subtract
    ;; 8 from the pen address.
    lda #$01
    sta pen_pixel_bit
    lda #$f8
    clc
    adc pen_addr_lo
    sta pen_addr_lo
    bcs +
    dec pen_addr_hi
+   rts
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="highlight-none notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span/&gt;;; pen_move_right: Move the pen one pixel row right on the
;; display.
pen_move_right:
    ;; Shift the pixel column bit right and store.
    lda pen_pixel_bit
    lsr
    sta pen_pixel_bit
    bne +
    ;; If we shifted out of the right, put the bit back into
    ;; the left side of the value, and move to the same
    ;; pixel row in the next cell; add 8 to the pen address.
    lda #$80
    sta pen_pixel_bit
    lda #$08
    clc
    adc pen_addr_lo
    sta pen_addr_lo
    bcc +
    inc pen_addr_hi
+   rts
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="highlight-none notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span/&gt;;; pen_px_set: Set the bitmap memory bit representing the
;; current pixel position to 1.
pen_px_set:
    lda pen_pixel_bit
    ldx #$00
    ora (pen_addr_lo,x)
    sta (pen_addr_lo,x)
    rts
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Here is the complete &lt;a class="reference external" href="../_static/c64-3d-graphics-series/pen.asm"&gt;pen source file&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We can draw any shape we want from our assembly language programs using these
pen routines.&lt;/p&gt;
&lt;p&gt;Here is a &lt;a class="reference external" href="../_static/c64-3d-graphics-series/test_pen.asm"&gt;test program&lt;/a&gt; that uses the
pen to draw straight lines from the right side of the display to the left, then
left to right, then top to bottom, then bottom to top.&lt;/p&gt;
&lt;img alt="../_images/test_pen.png" src="../_images/test_pen.png"/&gt;
&lt;p&gt;You might have noticed the line from right to left does not originate from the
far right side of the display. Examining our subroutine declaration again:&lt;/p&gt;
&lt;div class="highlight-none notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span/&gt;;; pen_move_to: Move the drawing pen to an (x, y) pixel
;; coordinate position on the display.
;; args
;;   y: y coordinate of the position
;;   x: x coordinate of the position
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;We take two arguments, y and x. Because x is supplied in an 8-bit memory
location, the maximum value of x is 255. However, the rightmost pixel column on
the display is 319. Because the size of the memory location that stores x is
smaller than 319, &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;pen_move_to&lt;/span&gt;&lt;/code&gt; can’t reach the right side of the display.
Since our geometry will not be drawn onto the far right of the display, this is
not a problem for our use case. If we want &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;pen_move_to&lt;/span&gt;&lt;/code&gt; to reach past column
255, we can do that by taking a third argument holding one extra bit for x.
When the bit is set, the column counter first counts to 255, then resets to
zero, then counts again until reaching the value of the “x” argument.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="wrapping-up"&gt;
&lt;h2&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;Here is a &lt;a class="reference external" href="../_static/c64-3d-graphics-series/c64-3d-graphics-series-part-1.zip"&gt;zip file&lt;/a&gt;
containing the test_bitmap and test_pen programs, as well as all the files
needed to build and run them.&lt;/p&gt;
&lt;p&gt;In the next part of this series, we implement routines to draw lines
directly from any pixel on the display to another, automatically calculating
all the pixels in between. Please contact me on &lt;a class="reference external" href="https://fosstodon.org/@daremo"&gt;the fediverse&lt;/a&gt; or &lt;a class="reference external" href="https://twitter.com/fmahnke"&gt;Twitter&lt;/a&gt;
with any questions or comments.&lt;/p&gt;
&lt;/section&gt;
</description><pubDate>Fri, 12 Apr 2019 00:00:00 </pubDate></item><item><title>The vale8 Instruction Set</title><link>http://www.mahnke.tech/blog/2019-04-12-the-vale8-instruction-set.html</link><description>

&lt;p&gt;&lt;em&gt;Published on 2019-04-12&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;One of the earliest challenges I faced when I decided to design a &lt;a class="reference external" href="2019-04-09-introducing-the-vale8x64-computer.html#bit-address-8-bit-data-cpu"&gt;custom CPU&lt;/a&gt;
for the vale8 was that, because I had almost no practical experience with
assembly language(s), I also had little intuition for knowing what instructions
to include in the CPU’s instruction set. My experience &lt;a class="reference external" href="2019-04-03-chaotic-first-post-of-2019.html#emulation"&gt;creating GB
and 8085 CPU emulators&lt;/a&gt;
was helpful in that I at least understood how to implement many common CPU
instructions. Regardless, it was clear I needed a wider perspective.&lt;/p&gt;
&lt;p&gt;There are other ways to approach designing a CPU’s ISA than from the viewpoint
of the assembly language programmer.  For example, if the CPU is mainly
intended to be used with one or more higher-level languages, it can implement
the minimum subset of instructions required by those languages.  However,
designing around support for higher level languages with no attention to the
assembly language could result in a product that’s unpleasant to program using
assembly language.&lt;/p&gt;
&lt;p&gt;While I am interested in implementing either Forth or BASIC on vale8
eventually, I’m going to keep them out of scope for now. That means assembly is
the single supported programming language for the first version of vale8. With
that in mind, my goal for the instruction set is for it to be as simple as it
can be while still being fun to program directly in assembly.&lt;/p&gt;
&lt;p&gt;To get a better sense of how “good” assembly languages feel, I’ve decided to do
some small projects in assembly language for one or more popular 8-bit
processors. I’ll take that practical experience back to the vale8 ISA design.&lt;/p&gt;
</description><pubDate>Fri, 12 Apr 2019 00:00:00 </pubDate></item><item><title>Introducing the vale8x64 Computer</title><link>http://www.mahnke.tech/blog/2019-04-09-introducing-the-vale8x64-computer.html</link><description>

&lt;p&gt;&lt;em&gt;Published on 2019-04-09&lt;/em&gt;&lt;/p&gt;
&lt;section id="history"&gt;
&lt;h2&gt;History&lt;/h2&gt;
&lt;p&gt;I missed the majority of the home computer revolution of the 1970s and ’80s.  If
I’d been born a few years earlier, I might have used an Apple IIe or Commodore
64 at home.  But Nintendo’s marketing game was strong and reached my brother and
me at young ages.  The NES became the first “computer” in our household. I was
fascinated by it, but the NES wasn’t presented as a personal computer. It didn’t
welcome exploration. I don’t recall ever feeling encouraged to take it apart to
get to know what was inside.&lt;/p&gt;
&lt;figure class="align-default"&gt;
&lt;a class="reference internal image-reference" href="../_images/2019-04-09_nes_action_set.jpg"&gt;&lt;img alt="../_images/2019-04-09_nes_action_set.jpg" src="../_images/2019-04-09_nes_action_set.jpg" style="width: 375.0px; height: 500.0px;"/&gt;
&lt;/a&gt;
&lt;/figure&gt;
&lt;p&gt;I don’t even remember having a concept of a home computer when we got our first
one. It had an 80286 CPU with MS-DOS 3.3, 1 MiB RAM, 5.25” floppy disk drive, 20
MB hard drive, CGA-compatible graphics and a monochrome monitor, custom built at
a local computer store.&lt;/p&gt;
&lt;p&gt;I was immediately interested in the machine. Information wasn’t as plentiful as
it is today, but was available in the computer’s manuals and from the owner
of the computer store.  I remember going to the library, finding the computer
section, and checking out my first programming book. I think &lt;a class="reference external" href="https://archive.org/details/invent-your-own-computer-games"&gt;this&lt;/a&gt; was it.&lt;/p&gt;
&lt;figure class="align-default" id="id1"&gt;
&lt;a class="reference internal image-reference" href="../_images/2019-04-09_invent_your_own.png"&gt;&lt;img alt="../_images/2019-04-09_invent_your_own.png" src="../_images/2019-04-09_invent_your_own.png" style="width: 253.0px; height: 309.0px;"/&gt;
&lt;/a&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;My first programming book.&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;That book introduced me to the BASIC programming language. Fortunately, DOS
provided a BASIC interpreter. I was able to start writing my first programs
using the examples in the book, which were simple number guessing games and
word games with shallow branching logic.&lt;/p&gt;
&lt;figure class="align-default" id="id2"&gt;
&lt;img alt="../_images/2019-04-09_gw-basic.png" src="../_images/2019-04-09_gw-basic.png"/&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;“Gee-Whiz” BASIC, the programming language bundled with MS-DOS.&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Not long after, we got Microsoft QuickBASIC. The manual had example programs.  I
was able to make most of the example programs work, but not all of them. I
didn’t comprehend what I was reading in the manual the way I would have needed
to use the language in a truly general purpose way. The results I created
were the best I could do at the time, but incomplete. But that was fine; I was
programming and I was happy.&lt;/p&gt;
&lt;figure class="align-default" id="id3"&gt;
&lt;img alt="../_images/2019-04-09_quickbasic.jpg" src="../_images/2019-04-09_quickbasic.jpg"/&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;The iconic QuickBASIC launch screen.&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I learned BASIC and QuickBASIC’s program structure well. Variables, for loops
and other control structures, and subroutines made sense. But I didn’t
understand the memory model. I didn’t know how to talk to the computer’s
hardware. I didn’t know what assembly language was. I was vaguely aware that
there were ways to program the computer other than BASIC and QuickBASIC. I knew
there were things called binary and hexadecimal, and I thought you could write
programs with them. Although I studied geometry, algebra, and calculus in high
school and university, I didn’t develop a joy or intuition for how math and
programming intertwine during that time.  With regard to deeply understanding
computers, I kind of got myself stuck. I resigned myself to being an expert
computer operator, but only a casual computer programmer, for many years.&lt;/p&gt;
&lt;p&gt;Over time, and with much help, I eventually improved at programming to the point
that I can now demonstrably be paid to it. I have better intellect and focus to
understand the things I couldn’t before. But commercial software development
practices and modern consumer hardware favor using libraries, frameworks, and
other layers of abstraction over really knowing what happens inside the machine
and programming directly against its hardware. And the layers of abstraction
increase with each new generation of consumer computers and OS software.&lt;/p&gt;
&lt;p&gt;I think there was a time when it was more natural to learn the fundamentals of
computing as part of being either a computer enthusiast or professional. In this
sense, my comprehension came too late; I had missed out on the first era of low
level computing in popular culture.&lt;/p&gt;
&lt;p&gt;In the present moment, near future, and near past, I only consider a small slice
of all the possible choices and outcomes. Planning into the future is done using
a small known set of alternatives, compared to what we learn was possible in
retrospect.  Perspective widens as history moves further away; looking at time
passed, I can see everything I did, but also everything I couldn’t or chose not
to do at any time.  It’s sometimes natural to see things not done as missed
opportunities.  But this is only true if the window of opportunity has actually
passed.  Otherwise, the feeling of having missed out is erroneous; realizing
there’s something valuable left undone isn’t identifying a missed opportunity,
it’s identifying a new one.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="beginnings-from-breadboard-to-fpga"&gt;
&lt;h2&gt;Beginnings (from Breadboard to FPGA)&lt;/h2&gt;
&lt;p&gt;After I started studying electronics and computer architecture last year, I
started designing my own computer. I committed to creating most major components
(RAM is an exception) from first principles, down to and including its
processor. This has become a major project that I’ve named vale8x64 (vale8 for
short). I see vale8 as one opportunity to fill gaps in my understanding of
technology and gain the experience I previously missed.  The exercise of
creating vale8 is my means of learning computing down to the metal, silicon, and
logic.  &lt;a class="reference external" href="https://gitlab.com/vale-computer/vale8x64"&gt;It’s free, with all HDL and software licensed under GPLv3 from the
beginning&lt;/a&gt;, in case what I learn
during this project will eventually be helpful to someone else as well.&lt;/p&gt;
&lt;p&gt;Although I can trace its roots back to my growing interest in &lt;a class="reference external" href="2019-04-03-chaotic-first-post-of-2019.html#emulation"&gt;emulation&lt;/a&gt;, vale8 really began
when I started &lt;a class="reference external" href="2019-04-03-chaotic-first-post-of-2019.html#homebrew-computers"&gt;working with TTL logic&lt;/a&gt;.  Throwing
logic chips on breadboards was a fun and tangible way to start building a
computer, with the wiring helping me visualize how data flows on the bus.  But I
quickly grew frustrated with the high cost of parts and long iteration times.
Routing and wiring on a breadboard takes careful planning, especially if wiring
is to stay neat, so the breadboard method didn’t lend itself to long-term
experimentation. I started to look for alternatives.&lt;/p&gt;
&lt;p&gt;I knew FPGAs existed and understood them as a way to implement reconfigurable
hardware using a programming language, but didn’t understand at all how they
worked.  I began researching and learning VHDL and Verilog. I reproduced what I
had done on the breadboards in VHDL and simulated the results using &lt;a class="reference external" href="http://ghdl.free.fr/"&gt;GHDL&lt;/a&gt;. After I’d reached parity between the breadboard design
and the VHDL version and felt like I conceptually understood how an HDL
describes hardware, I started to look into FPGA boards.&lt;/p&gt;
&lt;p&gt;I use &lt;a class="reference external" href="https://www.gnu.org/philosophy/free-sw.html"&gt;free software&lt;/a&gt; as
exclusively as possible, so the first criterion I chose for my search was a free
software toolchain. I was surprised to find only one: &lt;a class="reference external" href="http://www.clifford.at/icestorm/"&gt;Project Icestorm&lt;/a&gt;. Apparently the development tooling for
FPGAs in general is in a pretty backwards state, with most vendors supplying
bloated, node-locked proprietary software packages and keeping the FPGA
bitstream details locked away, slowing development of free software
alternatives.  I was grateful to find IceStorm and familiarized myself with the
specs for the &lt;a class="reference external" href="http://www.latticesemi.com/en/Products.aspx#_D5A173024E414501B36997F26E842A31"&gt;Lattice iCE40&lt;/a&gt;
line of FPGAs, which is what IceStorm currently supports. I found the &lt;a class="reference external" href="https://www.latticesemi.com/icestick"&gt;iCEstick&lt;/a&gt;, a starter board in a USB stick form
factor, and ordered it.&lt;/p&gt;
&lt;figure class="align-default"&gt;
&lt;img alt="../_images/2019-04-09_icestick.png" src="../_images/2019-04-09_icestick.png"/&gt;
&lt;/figure&gt;
&lt;p&gt;I knew I would hit the iCEstick’s limitations pretty quickly. In particular,
there wouldn’t be enough GPIO pins to do both VGA and serial I/O at the same
time. But since I’d yet to synthesize my first bitstream and program it to an
FPGA, it seemed like a good place to start.&lt;/p&gt;
&lt;p&gt;I converted all my VHDL to Verilog, since IceStorm doesn’t currently support
VHDL. I reached and surpassed my breadboard design, creating a turing complete
CPU with a minimal instruction set on the iCEstick board.&lt;/p&gt;
&lt;p&gt;It’s been a pleasure so far to use the IceStorm toolchain in my Make-driven
workflow and to read its documentation. IceStorm makes me feel like I’ve gotten
into FPGA development at a great time.&lt;/p&gt;
&lt;p&gt;I filled the iCEstick’s &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Logic_block"&gt;PLBs&lt;/a&gt; to
capacity, and
then ordered the &lt;a class="reference external" href="http://www.latticesemi.com/en/Products/DevelopmentBoardsAndKits/iCE40UltraPlusBreakoutBoard"&gt;UP5K breakout board&lt;/a&gt;
to give myself more PLB and I/O capacity.  The UP5K is what I’m currently using
to develop vale8.&lt;/p&gt;
&lt;figure class="align-default"&gt;
&lt;img alt="../_images/2019-04-09_ice40_up5k.png" src="../_images/2019-04-09_ice40_up5k.png"/&gt;
&lt;/figure&gt;
&lt;/section&gt;
&lt;section id="specs"&gt;
&lt;h2&gt;Specs&lt;/h2&gt;
&lt;p&gt;Here are the currently planned specs for the first version of the vale8 product
and some notes on each.&lt;/p&gt;
&lt;section id="bit-address-8-bit-data-cpu"&gt;
&lt;h3&gt;16-bit address/8-bit data CPU&lt;/h3&gt;
&lt;p&gt;I’m developing a custom processor to act as vale8’s CPU. It is influenced by
RISC-V, &lt;a class="reference external" href="https://zipcpu.com/"&gt;ZipCPU&lt;/a&gt;, and others.&lt;/p&gt;
&lt;p&gt;I’ve created several iterations of the CPU’s &lt;a class="reference external" href="https://gitlab.com/vale-computer/vale8x64/blob/master/asm/inst_generate.py"&gt;instruction set&lt;/a&gt;
so far, learning from mistakes each time. I expect several further iterations
before the &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Instruction_set_architecture"&gt;ISA&lt;/a&gt;
is final.&lt;/p&gt;
&lt;p&gt;The CPU clock speed is to be determined, because it depends on the final
configuration of the peripherals and external memory, which is also to be
determined.&lt;/p&gt;
&lt;p&gt;A 16-bit address width allows the processor to address up to 64 KiB of memory.&lt;/p&gt;
&lt;p&gt;8-bit data seems to be a good balance between minimalism and ability for
creative expression.  The &lt;a class="reference external" href="https://www.youtube.com/watch?v=5MexnBunH_g"&gt;demoscene&lt;/a&gt; started on machines with 8-bit
processors.&lt;/p&gt;
&lt;p&gt;8 bits is also a good size for a programmer to practice use of full adder logic,
since add with carry is frequently used to operate with numbers larger than 8
bits.&lt;/p&gt;
&lt;p&gt;16-bit address/8-bit data width is a common configuration for 8-bit processors
of the day, notably the 6502, 8085, and Z80.&lt;/p&gt;
&lt;figure class="align-default" id="id4"&gt;
&lt;a class="reference internal image-reference" href="../_images/2019-04-09_6502.gif"&gt;&lt;img alt="../_images/2019-04-09_6502.gif" src="../_images/2019-04-09_6502.gif" style="width: 198.5px; height: 385.0px;"/&gt;
&lt;/a&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;6502 Pinout, with 16 address lines and 8 data lines.&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/section&gt;
&lt;section id="memory-mapped-i-o"&gt;
&lt;h3&gt;Memory-mapped I/O&lt;/h3&gt;
&lt;p&gt;With memory-mapped I/O, both the computer’s memory and its I/O devices use the
same address space. In other words, communicating with an I/O device is done
simply by reading from or writing to a location in memory.&lt;/p&gt;
&lt;p&gt;This is a very simple way to do I/O, and since vale8 has a small number of I/O
peripherals, the impact on available system memory should be acceptable.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="rs-232-serial-port-i-o"&gt;
&lt;h3&gt;RS-232 Serial Port I/O&lt;/h3&gt;
&lt;p&gt;The serial port can be used to exchange data between the vale8
computer and a different computer over a serial cable. In this way, you can use
another computer to reprogram
the vale8’s memory. You can also type commands to it interactively with the other
computer’s keyboard.&lt;/p&gt;
&lt;p&gt;Supporting serial communication delays the need for both persistent program
storage and a keyboard controller.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="character-cell-vga-graphics"&gt;
&lt;h3&gt;Character Cell VGA Graphics&lt;/h3&gt;
&lt;p&gt;Character cell graphics is a system in which the display is arranged in rows and
columns of characters of equal dimensions.  For example, the display may be 320x240
pixels and 40x30 characters. In this case, each character is 8x8 pixels.&lt;/p&gt;
&lt;p&gt;The running program selects the character to be used in each row and column of the display from the set of available characters in the computer’s memory. In this way, the
program chooses what combination of letters, numbers, or graphical characters
appear on the screen to make text or graphics.&lt;/p&gt;
&lt;p&gt;The computer usually
provides a standard set of characters for convenience, but characters
may also be reprogrammable.&lt;/p&gt;
&lt;p&gt;Now that we’ve discussed character cell graphics in general, here’s a test
image from an early version of the vale8 VGA controller.&lt;/p&gt;
&lt;img alt="../_images/2019-04-09_vga_controller.jpg" src="../_images/2019-04-09_vga_controller.jpg"/&gt;
&lt;p&gt;vale8’s display resolution, character dimensions and number of available colors are
to be determined, although the
first version is likely to support one color (monochrome).&lt;/p&gt;
&lt;p&gt;I plan for the VGA controller to support programmable characters. In lieu of full
bitmap graphics support, this provides some ability to customize graphics.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="sound-generator"&gt;
&lt;h3&gt;Sound Generator&lt;/h3&gt;
&lt;p&gt;I’m inspired by subtractive synthesizers like the NES APU and the SID (used in
the Commodore 64). The target for the Vale Audio Unit (VAU) is a 4-oscillator
sound generator, with each voice independently supporting triangle,
variable-duty pulse wave, sawtooth, and noise waveforms. I’m working on the VAU
presently, and specs may change depending on what fits on the final FPGA’s
resources.&lt;/p&gt;
&lt;p&gt;See the &lt;a class="reference external" href="https://gitlab.com/vale-computer/vtracker"&gt;vtracker&lt;/a&gt; repository if
interested in following the progress of the VAU. I’m developing a tracker (music
sequencer) along with the VAU itself.&lt;/p&gt;
&lt;iframe src="https://fosstodon.org/@daremo/101710324844387543/embed" class="mastodon-embed" style="max-width: 100%; border: 0" width="400"/&gt;&lt;/section&gt;
&lt;section id="hosted-machine-code-monitor"&gt;
&lt;h3&gt;Hosted Machine Code Monitor&lt;/h3&gt;
&lt;p&gt;The &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Machine_code_monitor"&gt;machine code monitor&lt;/a&gt;
is among the most fundamental user programs, so vale8’s ROM will include one.
The CPU instruction set has a BRK (“break”) instruction that saves the CPU state
and then then jumps into the machine code monitor for interactive debugging.&lt;/p&gt;
&lt;iframe src="https://fosstodon.org/@daremo/101602847953919584/embed" class="mastodon-embed" style="max-width: 100%; border: 0" width="400"/&gt;&lt;script src="https://fosstodon.org/embed.js" async="async"/&gt;&lt;/section&gt;
&lt;section id="non-hosted-assembler-for-writing-programs"&gt;
&lt;h3&gt;Non-hosted Assembler for Writing Programs&lt;/h3&gt;
&lt;p&gt;There’s a long standing tradition of using more powerful development
workstations to write programs targeting less powerful computers. While vale8
could eventually support a hosted assembler (one that runs on vale8 itself), the
initial workflow is to assemble programs on an x64 workstation and then put them
on the vale8 over serial connection.&lt;/p&gt;
&lt;p&gt;This allows you to take advantage of the power and tools of modern computers to
write programs for vale8, and delays the requirement to write an assembler and
text editor for vale8 itself.&lt;/p&gt;
&lt;p&gt;I’m on the &lt;a class="reference external" href="https://gitlab.com/vale-computer/vale8x64/blob/master/asm/asm.py"&gt;second from-scratch iteration of the assembler&lt;/a&gt;. I wrote
both the first and second versions in Python. I’ll write the next one in C.&lt;/p&gt;
&lt;img alt="../_images/2019-04-09_assembler.jpg" src="../_images/2019-04-09_assembler.jpg"/&gt;
&lt;p&gt;The vale8 assembler supports named labels, forward and backward unnamed labels,
and rudimentary macros. It also supports emitting the final positioned machine
code with the assembly source code next to it, which is convenient for
debugging.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="memory"&gt;
&lt;h3&gt;Memory&lt;/h3&gt;
&lt;p&gt;The current development workflow uses the FPGA’s embedded block RAM. This has
been convenient for development to this point, but it is too limited for
the finished product.&lt;/p&gt;
&lt;p&gt;The UP5K FPGA board doesn’t have enough GPIO to add external memory to the
configuration, nor have I investigated suitable RAM options in general.  I’ll
work on this sometime after upgrading to the HX8K FPGA.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="development-plan"&gt;
&lt;h2&gt;Development Plan&lt;/h2&gt;
&lt;p&gt;Since I’m currently working on the sound generator, the next step is to finish a
working prototype of that and test it with the rest of the system.&lt;/p&gt;
&lt;p&gt;I plan to upgrade from the UP5K to the &lt;a class="reference external" href="https://www.latticesemi.com/Products/DevelopmentBoardsAndKits/iCE40HX8KBreakoutBoard.aspx"&gt;HX8K breakout board&lt;/a&gt;.
I may do this around the same time as integrating the sound generator, because
GPIO on the UP5K is getting tight.&lt;/p&gt;
&lt;p&gt;I’m optimistic the HX8K board will have enough PLBs and I/O for the final CPU,
peripheral and memory configuration.  I plan to go no larger than the HX8K for
the first version of vale8.&lt;/p&gt;
&lt;p&gt;I’ve put some deliberate constraints on vale8’s specs, to keep its scope to what
I think I can complete in 2019. I plan to work on it roughly full-time until
it’s finished. What happens after that is unknown.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="goodbye"&gt;
&lt;h2&gt;Goodbye&lt;/h2&gt;
&lt;p&gt;Thanks for reading. If you’re interested in this project, you might
like to subscribe to my &lt;a class="reference external" href="../rss.xml"&gt;RSS feed&lt;/a&gt; and &lt;a class="reference external" href="https://fosstodon.org/@daremo"&gt;follow&lt;/a&gt; my &lt;a class="reference external" href="https://twitter.com/fmahnke"&gt;progress&lt;/a&gt;.
It’s important to me to learn from the computer engineering community as I work
on this. I welcome and appreciate questions and suggestions.&lt;/p&gt;
&lt;/section&gt;
</description><pubDate>Tue, 09 Apr 2019 00:00:00 </pubDate></item><item><title>Chaotic First Post of 2019</title><link>http://www.mahnke.tech/blog/2019-04-03-chaotic-first-post-of-2019.html</link><description>

&lt;p&gt;&lt;em&gt;Published on 2019-04-03&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This is the hopefully better-late-than-never first post of the great new year
of 2019.  It’s been a long time since my last post here. For several months, I
was playing around with a lot of new ideas and was more comfortable doing short
updates on Mastodon. That has settled down a bit and my focus for 2019 is set.&lt;/p&gt;
&lt;p&gt;Much has happened, so this Chaotic First Post of 2019 is a good way for me to
organize the jumbled events of the past year and reflect on them.&lt;/p&gt;
&lt;section id="what-i-did-in-tech"&gt;
&lt;h2&gt;2018: What I Did in Tech&lt;/h2&gt;
&lt;section id="game-engine-and-graphics-programming"&gt;
&lt;h3&gt;Game Engine and Graphics Programming&lt;/h3&gt;
&lt;p&gt;In early 2018, I began creating my first game engine using Python/OpenGL and
participated in the OGAM game jam for a few months.  I wrote about that
extensively on this blog. Writing a game engine was a great way to build more
experience with geometry and matrix operations in computer graphics. Python was
a great prototyping engine for ideas. Through that project, I came to really
appreciate Python as a prototyping tool. That’s not to say it’s not appropriate
for production. I think it is, in its domains. But I think it really shines for
iterating over designs quickly (I also used Python to start the &lt;a class="reference external" href="https://gitlab.com/vale-computer/vale8x64/tree/master/asm"&gt;vale8x64
assembler&lt;/a&gt;, but
more on that another time).&lt;/p&gt;
&lt;p&gt;When adding support for particle systems, I noticed some frame rate issues
with the engine and did several &lt;a class="reference external" href="2018-05-26-performance-tools.html"&gt;rounds&lt;/a&gt;
of &lt;a class="reference external" href="2018-06-04-optimizing-matrix-operations.html"&gt;performance optimization&lt;/a&gt;. I
think I could have continued to optimize and develop the engine in Python for
quite awhile, had I moved engine code into a separate thread and re-evaluated
some design decisions. But it was too late; I had started learning Rust and was
eager to use it.&lt;/p&gt;
&lt;p&gt;I managed to port much of my engine code to Rust in my first few weeks of
learning it. I was impressed with the maturity of the available libraries
(crates), the quality of the documentation, and the helpfulness of the
community to beginners. But I quickly learned that certain fundamental data
structures and patterns are difficult to implement in safe Rust. Examples from
my engine include the entity graph, a tree-like structure used to store
and manipulate game object state, and the callback-based global event system.
Nonetheless, I enjoyed using Rust and learned to either make the extra
effort or drop into unsafe Rust to work around these issues.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="emulation"&gt;
&lt;h3&gt;Emulation&lt;/h3&gt;
&lt;p&gt;After learning basic Rust and porting the game engine, I discovered and
followed the &lt;a class="reference external" href="http://emulator101.com/"&gt;Emulator 101&lt;/a&gt; series, using Rust
instead of C, and created a Space Invaders emulator. This was my first foray
into emulation, and it really hooked me.&lt;/p&gt;
&lt;figure class="align-default"&gt;
&lt;img alt="../_images/space_invaders_2019-04-02.jpg" src="../_images/space_invaders_2019-04-02.jpg"/&gt;
&lt;/figure&gt;
&lt;p&gt;Looking for another emulation fix, I went on to create a partial Game Boy
emulator in Rust.&lt;/p&gt;
&lt;figure class="align-default"&gt;
&lt;img alt="../_images/dr_mario_2019-04-02.jpg" src="../_images/dr_mario_2019-04-02.jpg"/&gt;
&lt;/figure&gt;
&lt;p&gt;There was something about emulation that felt fundamentally cool, but also
felt &lt;em&gt;novel&lt;/em&gt; and, in certain ways, unlike other programming I’d done before.&lt;/p&gt;
&lt;p&gt;Abstractly and briefly, making software emulation is about learning the
implementation details of some system, and then writing software to
reproduce the behavior of that system as closely as is practical and necessary.&lt;/p&gt;
&lt;p&gt;I wonder if it stimulates the brain in the same way as world-building activities
and simulation/building games. That’s kind of what doing emulation feels like
to me.&lt;/p&gt;
&lt;p&gt;This new and exciting area came with a set of unique challenges that can make
it very difficult.&lt;/p&gt;
&lt;p&gt;The specifications of the target system may not be well-defined enough to
emulate. For example, a CPU’s reference manual may have incomplete or incorrect
documentation of an instruction’s behavior (I’m looking at the DAA instruction
on the Game Boy processor, and &lt;a class="reference external" href="https://ehaskins.com/2018-01-30%20Z80%20DAA/"&gt;this guy&lt;/a&gt; had the same problem; it’s
common).&lt;/p&gt;
&lt;p&gt;Likewise, a CPU instruction could have bugs in corner cases where it doesn’t
behave as defined. But software for the system may rely on those bugs being
there. From memory, I think I had this problem with the DAA instruction on
the Intel 8080, but I’m not certain.&lt;/p&gt;
&lt;p&gt;In either of the above cases, you could implement the instruction with correct
logic, as defined in whatever documentation you have, but get unexpected
results in emulation. A popular system is likely to have existing emulators and
a community behind it to help. If you were emulating an exotic piece of
hardware and no prior work were available to reference, one solution to this
problem might be to get a working unit, write test cases for all known inputs
to the problematic routine, and work out the behavior by analyzing the outputs.&lt;/p&gt;
&lt;p&gt;Another challenge of emulation is that potential documentation gaps and
idiosyncratic behavior in the target system can make it difficult to write
a thorough set of test cases to verify the expected behavior. The best
pre-existing test cases may be complete programs that require a large part of
the system to be emulated correctly to do anything interesting. Until you get
there, you can step through one instruction at a time with your disassembler
and compare the system state with that of another emulator, if available.&lt;/p&gt;
&lt;p&gt;Emulation has influenced my view on proprietary hardware and software systems
(as opposed to free/libre ones). There was a magical feeling juxtaposed with
the tedium of debugging as I used the disassemblers I wrote for these
processors to step through the Space Invaders and Dr. Mario programs. In
retrospect, I was developing a new perspective on “openness”: with sufficient
knowledge and methods of observation, using the words “proprietary” or “closed”
to describe a system is meaningless. All human-made systems obfuscated either
intentionally or by omission of information are eventually reverse engineered
using the same methods and tools we’ve used to learn the mechanisms behind
natural phenomena. In this sense, can the implementation details of a system be
the “secret” property of any person or other entity, any more than undiscovered
secrets of nature are property of the universe? The legal system around
intellectual property adds gray color to this black and white shift in my
perspective, and has raised ethical implications I continue to think about. I
want to discuss and debate this.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="homebrew-computers"&gt;
&lt;h3&gt;Homebrew Computers&lt;/h3&gt;
&lt;p&gt;In the background during all this, I was working through the
&lt;a class="reference external" href="https://www.allaboutcircuits.com/"&gt;All About Circuits textbook&lt;/a&gt; and
assembling the experiments. Things became really interesting when I got to the
digital section and starting learning about semiconductors and digital logic.&lt;/p&gt;
&lt;p&gt;I found TTL computers like the Gigatron and Ben Eater’s &lt;a class="reference external" href="https://eater.net/"&gt;8-bit breadboard
computer&lt;/a&gt;. After several months of working on 8-bit
emulators and building small breadboard projects, creating a hardware CPU
seemed like a natural next step. I ordered a lot of 7400 series TTL logic ICs
from Ali Express and went through most of the material in Digital Computer
Electronics (Malvino and Brown) thoroughly, careful to do each exercise and
completely understand each logic circuit in the book. As the 7400 parts came, I
used Eater’s tutorials and the schematics from the DCE book to do a partial CPU
implementation on breadboards. That was the start of &lt;a class="reference external" href="https://gitlab.com/vale-computer"&gt;vale8x64&lt;/a&gt;, the major project of 2019 which I’ll
review in more detail in a future post.&lt;/p&gt;
&lt;figure class="align-default"&gt;
&lt;img alt="../_images/breadboard_computer_2019-04-02.jpg" src="../_images/breadboard_computer_2019-04-02.jpg"/&gt;
&lt;/figure&gt;
&lt;/section&gt;
&lt;section id="social-and-mastodon"&gt;
&lt;h3&gt;Social and Mastodon&lt;/h3&gt;
&lt;p&gt;In 2018, I made an effort to make frequent short-form updates on my projects.
I chose to make my updates on Twitter, Mastodon, and Instagram.&lt;/p&gt;
&lt;p&gt;Suffice it to say that I’ve found a great home on &lt;a class="reference external" href="https://joinmastodon.org/"&gt;Mastodon&lt;/a&gt; (specifically, on the &lt;a class="reference external" href="https://fosstodon.org"&gt;Fosstodon&lt;/a&gt; instance). I’m impressed with the user experience on
the fediverse. I’ve met other hardware enthusiasts and other interesting
people and am happy to have found an instance where I can network with
other Free/Libre advocates. I still post to the other platforms, but the
majority of my social networking is on Mastodon, and I expect that to be the
case for 2019 and beyond.&lt;/p&gt;
&lt;p&gt;If you’re interested in building community on &lt;a class="reference external" href="https://docs.joinmastodon.org/usage/decentralization/"&gt;decentralized services&lt;/a&gt;, I recommend
Mastodon. It’s now my preferred contact method, along with email.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="things-i-learned"&gt;
&lt;h2&gt;2018: Things I Learned&lt;/h2&gt;
&lt;section id="more-comfort-in-inexperience"&gt;
&lt;h3&gt;More Comfort in Inexperience&lt;/h3&gt;
&lt;p&gt;Sort of. In 2018, I was uncomfortable developing my projects in
public repositories, self-conscious to show my low-quality prototypes and
inexperience in the new domains where I’ve chosen to put my time lately. I
thought I’d get each project finished (whatever that means), and then to some
admirable state of quality, and then release it under a libre license. I’ve
realized some things that have changed my habits recently.&lt;/p&gt;
&lt;p&gt;It’s irrational to be self-conscious about publishing my work in new areas.
Few people are likely to use their time to look at what I’ve pushed to
gitlab. If anything I do becomes significant enough that the way I did it is
problematic, that’s an okay problem.&lt;/p&gt;
&lt;p&gt;It’s not productive to wait for mastery of a domain before trying to contribute
in its community. There’s always more to know.  There is more than one topic in
which any person is a novice for each topic in which that person is an expert.
That will be the case for every person’s natural life. Thus, it makes sense to
make an effort to contribute at all skill levels. This is part of having a
growth mindset.&lt;/p&gt;
&lt;p&gt;Developing in public is a great way to improve skill in a new area. More
experienced people are happy to hone their experience by taking time to do
design and &lt;a class="reference external" href="http://anycpu.org/forum/viewtopic.php?f=13&amp;amp;t=569"&gt;code reviews for novices&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Releasing early is a great way for me to practice quality. If no one else
is looking, it’s tempting to ignore proper error handling, memory management,
and other good practices perpetually, promising to do it later (I’ve started to
call this arrangement “practicing prototyping”). On the other hand, if someone
else can see my work, I’m motivated to show my best work.  The larger a
project grows without attention to all the fine details, the larger the effort
required to retroactively address those details when they matter; prototyping
for too long puts the quality of the product at risk. So
committing to frequent and early releases of whatever slice of functionality I
make is a great motivator to practice good habits throughout the development
lifecycle.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="feeling-stupid-is-good"&gt;
&lt;h3&gt;Feeling Stupid Is Good&lt;/h3&gt;
&lt;p&gt;Put less bluntly, I’m becoming less likely to feel inadequate or frustrated
when I’m unable to understand a topic or complete a task easily, and more
likely to see it a signal that I’m expanding the limits of my capabilities.
Said a different way, I’m getting better at re-framing discouragement as
motivation. It seems like an obvious thing when I view it in writing, but is a
perspective shift for me regardless.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="more-politics"&gt;
&lt;h3&gt;More Politics?&lt;/h3&gt;
&lt;p&gt;Privacy and software ethics concern me more and more. As I see privacy become
more intertwined with the “data economy”, and service providers’ abuse of users
and customers become more bold and pervasive, my position against proprietary
(obfuscated) software and hardware becomes more extreme. I initially wanted to
keep my ‘net presence purely technical, but I may re-evaluate that and start to
write more about tech politics at some time.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="bye"&gt;
&lt;h2&gt;Bye&lt;/h2&gt;
&lt;p&gt;Thanks for reading my 2018 retrospective. In the next post, I’ll talk more about
building homebrew computers and give an overview of the vale project.&lt;/p&gt;
&lt;p&gt;If you found any of this post interesting, valuable, or
debatable, I’d &lt;a class="reference external" href="https://fosstodon.org/@daremo"&gt;enjoy&lt;/a&gt; the
&lt;a class="reference external" href="https://twitter.com/fmahnke"&gt;conversation&lt;/a&gt;.&lt;/p&gt;
&lt;/section&gt;
</description><pubDate>Wed, 03 Apr 2019 00:00:00 </pubDate></item><item><title>Optimizing Matrix Operations</title><link>http://www.mahnke.tech/blog/2018-06-04-optimizing-matrix-operations.html</link><description>

&lt;p&gt;&lt;a class="reference external" href="2018-05-26-performance-tools.html"&gt;Last time&lt;/a&gt;, we reviewed some major frame
rate issues I found in &lt;a class="reference external" href="2018-03-11-introducing-ng-engine.html"&gt;ng&lt;/a&gt; and
established a process to measure and improve on the problem. We reviewed
performance of a long-running test and identified the 4x4 matrix and vector
modules as major culprits. Today, we’ll do line-by-line analysis of the slow
parts and review my progress optimizing them.&lt;/p&gt;
&lt;section id="performance-analysis"&gt;
&lt;h2&gt;Performance Analysis&lt;/h2&gt;
&lt;p&gt;Recapping the last measurements, here are the most expensive functions for the
5 worst exceptional frames, according to callgrind. This list was generated by
the performance tool I wrote to do this exceptional frame analysis.&lt;/p&gt;
&lt;div class="highlight-text notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span/&gt;Frame  # ms/frame  call site

25798  4167.96     /usr/lib/python3.6/site-packages/ng/math/vector.py:__init__
27314  4120.22     /usr/lib/python3.6/site-packages/ng/ng.py:_entities_velocity
24394  3972.68     /usr/lib/python3.6/site-packages/ng/math/matrix.py:__matmul_
21420  3672.30     /usr/lib/python3.6/site-packages/ng/ng.py:_entities_velocity
20191  3374.32     /usr/lib/python3.6/site-packages/ng/math/matrix.py:__init__
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The most expensive operations are initializing new matrix and vector class
instances and multiplying matrices. These math operations are used per frame,
per entity to update entity positions and to prepare MVP matrices for display
output.&lt;/p&gt;
&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;_entities_velocity&lt;/span&gt;&lt;/code&gt; indirectly uses vector operations through its own
function calls, so it may drop off the list when vector is optimized. We’ll
focus on vector and matrix right now.&lt;/p&gt;
&lt;p&gt;The goal of this session is to reduce the number of usages of the vector and
matrix modules, as well as to improve the performance of each usage.&lt;/p&gt;
&lt;p&gt;Let’s use &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;callgrind_annotate&lt;/span&gt;&lt;/code&gt; to get more information about the call
patterns. To reduce the number of calls to a function, we need to know who is
calling. We add the &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;--tree=caller&lt;/span&gt;&lt;/code&gt; option to get this info. To improve the
performance of the function, we need to know which lines perform worst. We add
the &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;--auto=yes&lt;/span&gt;&lt;/code&gt; option so callgrind will annotate the source lines of each
module with the amount of time spent in each line.&lt;/p&gt;
&lt;p&gt;Here are the header and the call tree for frame 25798, which give us more
details on calls to &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;vector.py:__init__&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight-text notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span/&gt;$ callgrind_annotate --auto=yes --tree=caller  emitter-25798.pstats.cg
--------------------------------------------------------------------------------
Profile data file 'emitter-25798.pstats.cg'
--------------------------------------------------------------------------------
Profiled target:  (unknown)
Events recorded:  ns
Events shown:     ns
Event sort order: ns
Thresholds:       99
Include dirs:
User annotated:
Auto-annotation:  on

--------------------------------------------------------------------------------
           ns
--------------------------------------------------------------------------------
4,167,334,999  PROGRAM TOTALS

--------------------------------------------------------------------------------
           ns  file:function
--------------------------------------------------------------------------------

      415,000  &amp;lt; /usr/lib/python3.6/site-packages/ng/ng.py:_entities_velocity (255x) []
       34,000  &amp;lt; /usr/lib/python3.6/site-packages/ng/render/__init__.py:normalized_vertices (32
x) []
       20,000  &amp;lt; /usr/lib/python3.6/site-packages/ng/entity.py:size:128 (8x) []
      521,000  &amp;lt; /usr/lib/python3.6/site-packages/ng/math/bounding_box.py:aa_box (492x) []
       14,000  &amp;lt; /usr/lib/python3.6/site-packages/ng/entity.py:origin:118 (8x) []
4,040,391,999  &amp;lt; /usr/lib/python3.6/site-packages/ng/math/vector.py:__iadd__ (242x) []
       26,000  &amp;lt; /usr/lib/python3.6/site-packages/ng/ng.py:entity_create (8x) []
       34,000  &amp;lt; /usr/lib/python3.6/site-packages/ng/entity.py:velocity:170 (8x) []
       87,000  &amp;lt; /usr/lib/python3.6/site-packages/ng/entity.py:__init__ (40x) []
    1,238,000  &amp;lt; /usr/lib/python3.6/site-packages/ng/render/opengl.py:_draw_entity (984x) []
      278,000  &amp;lt; /usr/lib/python3.6/site-packages/ng/math/vector.py:__mul__ (242x) []
      235,000  &amp;lt; /usr/lib/python3.6/site-packages/ng/entity.py:position:137 (250x) []
       11,000  &amp;lt; /usr/lib/python3.6/site-packages/ng/entity.py:scale:159 (8x) []
4,042,445,000  *  /usr/lib/python3.6/site-packages/ng/math/vector.py:__init__
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Most of the calls in the graph look innocuous at a glance. There may be
opportunity to optimize some of those call patterns later, but nothing stands
out since they are all necessary for the update routine. The calls to
&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;vector.py:__init__&lt;/span&gt;&lt;/code&gt; from &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;vector.py:__iadd__&lt;/span&gt;&lt;/code&gt; and &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;vector.py:__mul__&lt;/span&gt;&lt;/code&gt;
look suspicious, though.  These are bound methods used for class instantiation
and operator overloading. The callgrind analysis shows us the lines for
&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;__iadd__&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight-text notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span/&gt;      .      def __iadd__(self, other: Any) -&amp;gt; 'Vector':
147,000          other = Vector(other)
      .
      .          self.x += other.x
180,999          self.y += other.y
278,000  =&amp;gt; /usr/lib/python3.6/site-packages/ng/math/vector.py:__init__ (242x)
      .          self.z += other.z
      .
      .          return self
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This method overloads the &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;+=&lt;/span&gt;&lt;/code&gt; operator, performing vector addition with a
scalar value and mutating the original vector instance. This operation doesn’t
need to allocate a new vector, but the first line creates a new vector instance
from the user’s input. I intended this as a convenience, allowing the user to
call the method with another type such as a tuple. Removing this convenience
will significantly reduce the number of Vector allocations. Here’s the change:&lt;/p&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span/&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__iadd__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Vector&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Vector'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;
    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;
    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;__sub__&lt;/span&gt;&lt;/code&gt; and &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;__add__&lt;/span&gt;&lt;/code&gt; methods had a similar pattern, so I also
changed those.  With these changes, we can expect frame 25798 to be improved
and can move to frames 24394 and 20191. These both spend a lot of time in the
matrix module.  I did a quick comparison of 20191 and 24394 and saw that they
are similar, so we can review only 24394.&lt;/p&gt;
&lt;p&gt;Here are the callgrind header and tree for frame 24394.&lt;/p&gt;
&lt;div class="highlight-text notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span/&gt;$ callgrind_annotate --auto=yes --tree=caller  emitter-24394.pstats.cg
--------------------------------------------------------------------------------
Profile data file 'emitter-24394.pstats.cg'
--------------------------------------------------------------------------------
Profiled target:  (unknown)
Events recorded:  ns
Events shown:     ns
Event sort order: ns
Thresholds:       99
Include dirs:
User annotated:
Auto-annotation:  on

--------------------------------------------------------------------------------
           ns
--------------------------------------------------------------------------------
3,972,006,999  PROGRAM TOTALS

--------------------------------------------------------------------------------
           ns  file:function
--------------------------------------------------------------------------------

3,889,429,000  &amp;lt; /usr/lib/python3.6/site-packages/ng/entity.py:matrix_init (4074x) []
    2,352,000  &amp;lt; /usr/lib/python3.6/site-packages/ng/render/opengl.py:_render_entity (410x) []
    2,343,000  &amp;lt; /usr/lib/python3.6/site-packages/ng/render/opengl.py:_draw_entity (784x) []
3,881,484,999  *  /usr/lib/python3.6/site-packages/ng/math/matrix.py:__matmul__

   57,394,000  &amp;lt; /usr/lib/python3.6/site-packages/ng/render/opengl.py:_render_entity (198x) []
   59,996,999  &amp;lt; /usr/lib/python3.6/site-packages/ng/render/opengl.py:update (7x) []
   21,398,999  *  /usr/lib/python3.6/site-packages/ng/render/opengl.py:_render_entity

   30,022,000  &amp;lt; /usr/lib/python3.6/site-packages/ng/render/opengl.py:_render_entity (205x) []
   10,284,999  *  /usr/lib/python3.6/site-packages/ng/render/opengl.py:_draw_entity

    5,807,000  &amp;lt; /usr/lib/python3.6/site-packages/ng/math/matrix.py:__matmul__ (5268x) []
    5,807,000  *  ~:&amp;lt;built-in method numpy.core.multiarray.matmul&amp;gt;

    5,312,000  &amp;lt; /usr/lib/python3.6/site-packages/ng/math/matrix.py:__init__ (6767x) []
    5,312,000  *  ~:&amp;lt;built-in method numpy.core.multiarray.array&amp;gt;

    7,177,999  &amp;lt; /usr/lib/python3.6/site-packages/ng/entity.py:matrix_init (252x) []
3,882,551,000  &amp;lt; /usr/lib/python3.6/site-packages/ng/entity.py:position:137 (198x) []
   11,371,000  &amp;lt; /usr/lib/python3.6/site-packages/ng/entity.py:rotation:148 (211x) []
      819,000  &amp;lt; /usr/lib/python3.6/site-packages/ng/entity.py:children_add (6x) []
      135,000  &amp;lt; /usr/lib/python3.6/site-packages/ng/entity.py:scale:159 (6x) []
      151,999  &amp;lt; /usr/lib/python3.6/site-packages/ng/entity.py:origin:118 (6x) []
    4,083,000  *  /usr/lib/python3.6/site-packages/ng/entity.py:matrix_init
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The worst performer, &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;matrix.py:__matmul__&lt;/span&gt;&lt;/code&gt;, is the matrix multiplication
operator on the Matrix class. The engine makes heavy use of this operation
while calculating entity model matrices and while preparing MVP matrices for
display rendering.&lt;/p&gt;
&lt;p&gt;Again, there might be opportunity to improve caller efficiency, but let’s see
how we can optimize this method in the matrix module.&lt;/p&gt;
&lt;p&gt;Here are the line-by-line costs of the methods.&lt;/p&gt;
&lt;div class="highlight-text notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span/&gt;            .  class Matrix():
    3,702,999      def __init__(self, values):
    5,312,000  =&amp;gt; ~:&amp;lt;built-in method numpy.core.multiarray.array&amp;gt; (6767x)
    2,327,000  =&amp;gt; ~:&amp;lt;method 'tolist' of 'numpy.ndarray' objects&amp;gt; (6767x)
            .          self._np_array = np.array(values)
            .
            .          self.values = self._np_array.tolist()
            .
            .      def _columns(self):
            .          return len(self.values[0])
            .
3,881,484,999      def __matmul__(self, other):
    5,807,000  =&amp;gt; ~:&amp;lt;built-in method numpy.core.multiarray.matmul&amp;gt; (5268x)
    6,831,999  =&amp;gt; /usr/lib/python3.6/site-packages/ng/math/matrix.py:__init__ (5268x)
            .          return Matrix(np.matmul(self._np_array, other._np_array))
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The only purpose of the &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Matrix&lt;/span&gt;&lt;/code&gt; class is to be a wrapper around the numpy
array. The original ng Matrix class implemented matrix operations in Python.
That was slow, so I previously changed it to use a numpy array for its
underlying operations, leaving Matrix as a wrapper class.&lt;/p&gt;
&lt;p&gt;The price of the wrapper class is apparent; every time we create a new matrix
or multiply two matrices, we incur the cost of a new Python class instance that
serves only to create a new numpy array instance underneath it.&lt;/p&gt;
&lt;p&gt;Wrapping third party APIs is a good practice in certain languages and
situations, allowing one to protect one’s own APIs from changes to third party
APIs. In this case, though, performance is the larger consideration.&lt;/p&gt;
&lt;p&gt;If the wrapper class were very important to the design, one potential
optimization would be to rewrite the matrix class as a C library. In this case,
numpy is ubiquitous in the Python computation space and carries a stable API,
so I’m comfortable using it directly instead of wrapping it. I ditched the
Matrix class entirely and ng now directly uses numpy arrays for all matrix
operations.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="the-data"&gt;
&lt;h2&gt;The Data&lt;/h2&gt;
&lt;p&gt;Here’s the data from a new run measured after the changes. I reformatted it a
bit to compare it more easily with the data from the last run.&lt;/p&gt;
&lt;table class="docutils align-default"&gt;
&lt;thead&gt;
&lt;tr class="row-odd"&gt;&lt;th class="head"&gt;&lt;p&gt;Metric&lt;/p&gt;&lt;/th&gt;
&lt;th class="head"&gt;&lt;p&gt;Run 0&lt;/p&gt;&lt;/th&gt;
&lt;th class="head"&gt;&lt;p&gt;Run 1&lt;/p&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;Session length (s)&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;2467.48&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;628.72&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;ms/frame (mean)&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;87.80&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;64.17&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;ms/frame (median)&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;79.32&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;63.10&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;ms/frame (std dev)&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;75.96&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;15.68&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;Exceptional frames
(variation multiple &amp;gt; 0.5&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;96&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;46&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;sec/exceptional frame&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;td&gt;&lt;p&gt;25.70&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;13.67&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;ms/frame (mean)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;td&gt;&lt;p&gt;798.30&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;208.43&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;ms/frame (median)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;td&gt;&lt;p&gt;278.32&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;149.94&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;ms/frame (std dev)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;td&gt;&lt;p&gt;1029.25&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;144.21&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;Active entities (mean)&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;206.07&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;243.30&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;Active entities (median)&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;205.00&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;247.00&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;p&gt;Active entities (std dev)&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;17.90&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;21.54&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The first thing to highlight is this run length is much shorter than the last.
Because there will be several iterations of optimization, I decided to do
shorter 10 minute runs for the intermediate iterations.  The caveat is we can’t
directly compare the summary data from this run to the last; the decreased
session length affects the averaged data.&lt;/p&gt;
&lt;p&gt;That’s okay. Again, this will be a series of improvements. We don’t need to do
a direct session-to-session comparison to answer the questions I want to answer
right now.&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;Are there still exceptional frames?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If so, how often?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If so, are the exceptions getting worse over time?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The first two questions are answered by the summary data. Yes, there are still
exceptional frames. They happen several times per minute on average.&lt;/p&gt;
&lt;table class="docutils align-default"&gt;
&lt;thead&gt;
&lt;tr class="row-odd"&gt;&lt;th class="head"&gt;&lt;p&gt;Metric&lt;/p&gt;&lt;/th&gt;
&lt;th class="head"&gt;&lt;p&gt;Last Run&lt;/p&gt;&lt;/th&gt;
&lt;th class="head"&gt;&lt;p&gt;This Run&lt;/p&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr class="row-even"&gt;&lt;td&gt;&lt;p&gt;Exceptional frames
(variation multiple &amp;gt; 0.5&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;96&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;46&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="row-odd"&gt;&lt;td&gt;&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;sec/exceptional frame&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;td&gt;&lt;p&gt;25.70&lt;/p&gt;&lt;/td&gt;
&lt;td&gt;&lt;p&gt;13.67&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Let’s look at the graphs.&lt;/p&gt;
&lt;figure class="align-default"&gt;
&lt;img alt="../_images/2018-06-03_frame_rate_runtime_f74cde-nparray-opt.png" src="../_images/2018-06-03_frame_rate_runtime_f74cde-nparray-opt.png"/&gt;
&lt;/figure&gt;
&lt;figure class="align-default"&gt;
&lt;img alt="../_images/2018-06-03_frame_rate_variation_exc_f74cde-nparray-opt.png" src="../_images/2018-06-03_frame_rate_variation_exc_f74cde-nparray-opt.png"/&gt;
&lt;/figure&gt;
&lt;figure class="align-default"&gt;
&lt;img alt="../_images/2018-06-03_frame_rate_variation_f74cde-nparray-opt.png" src="../_images/2018-06-03_frame_rate_variation_f74cde-nparray-opt.png"/&gt;
&lt;/figure&gt;
&lt;p&gt;The spikes in the graph indicate the same pattern as before. The frame-to-frame
variation worsens over the length of the session.&lt;/p&gt;
&lt;p&gt;Here’s the new short list of expensive calls.&lt;/p&gt;
&lt;div class="highlight-text notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span/&gt;Frame # ms/frame  call site
8980  581.74      /usr/lib/python3.6/site-packages/ng/math/bounding_box.py:aa_box
8232  526.43      /usr/lib/python3.6/site-packages/ng/math/vector.py:__init__
7645  494.95      /usr/lib/python3.6/site-packages/ng/math/bounding_box.py:aa_box
6999  478.29      /usr/lib/python3.6/site-packages/ng/math/vector.py:__init__
6484  465.14      /usr/lib/python3.6/site-packages/OpenGL/wrapper.py:calculate_cArgs
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Finally, some good news. The matrix module has dropped off the list of worst
offenders and numpy’s array multiplication routines are not on the list. This
suggests replacing the matrix class with numpy arrays improved things. The
vector module is still there, indicating we might be able to improve it
further.  &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;boundingbox_py.aa_box&lt;/span&gt;&lt;/code&gt; is new to the list. That function uses the
vector module, so it’s reasonable to expect that vector is the bottleneck for
&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;aabox&lt;/span&gt;&lt;/code&gt;.  An internal call in the &lt;a class="reference external" href="http://pyopengl.sourceforge.net/"&gt;PyOpenGL&lt;/a&gt; library is also new to the list this time.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="next"&gt;
&lt;h2&gt;Next?&lt;/h2&gt;
&lt;p&gt;We could continue to optimize the vector module. However, I’m certain we can
make improvements there. I have less knowledge and certainty around the
PyOpenGL library, because it is third-party code. Also, since ng’s OpenGL
renderer is my first experience using OpenGL, I made some early design mistakes
and already have some TODO items to fix there. For these reasons, PyOpenGL is
the greater concern. I’ll leave the vector module for now and focus on
improving OpenGL usage next.&lt;/p&gt;
&lt;p&gt;Thanks for reading! Next time, we’ll look at my OpenGL optimizations, and
review measurements of another run.&lt;/p&gt;
&lt;/section&gt;
</description><pubDate>Mon, 04 Jun 2018 00:00:00 </pubDate></item><item><title>Performance Measurement and Tools</title><link>http://www.mahnke.tech/blog/2018-05-26-performance-tools.html</link><description>

&lt;p&gt;In computer software, performance improvement follows performance measurement.
After finishing some small &lt;a class="reference external" href="2018-05-21-dev-log.html"&gt;optimization sessions&lt;/a&gt;,
I decided to both define a repeatable performance measurement process and to
build tools to support it.  We’ll examine the process and initial measurements
in this post, and we’ll review my progress in the next few posts.&lt;/p&gt;
&lt;p&gt;I’m interested in measuring two general conditions. The first is the average
state of things over the lifetime of the application. The second is the
instantaneous state of things; conditions at a given moment in time.  Average
information is helpful for optimizing to improve average frame rate.
Instantaneous information is helpful for optimizing exceptional behavior. The
sudden frame rate drops I’ve been seeing are exceptional behavior.  Analyzing
average performance data doesn’t reveal them; they’re hidden in the averaging.&lt;/p&gt;
&lt;section id="the-process"&gt;
&lt;h2&gt;The Process&lt;/h2&gt;
&lt;p&gt;Here’s the initial process I’ve adopted for average measurement and
optimization.&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;&lt;p&gt;Run a timed test of application code in question under &lt;a class="reference external" href="https://docs.python.org/3/library/profile.html"&gt;cProfiler&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Analyze cProfiler results with &lt;a class="reference external" href="https://pypi.org/project/snakeviz/"&gt;snakeviz&lt;/a&gt; or &lt;a class="reference external" href="http://valgrind.org/docs/manual/cl-manual.html#cl-manual.callgrind_annotate-options"&gt;callgrind_annotate&lt;/a&gt;.
Select a function to optimize.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Analyze the cost of the selected function using callgrind_annotate and
&lt;a class="reference external" href="https://pypi.org/project/line_profiler/"&gt;line_profiler&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Make code changes. Run another timed test. Compare results and repeat until
satisfied.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Commit changes.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This one is for instantaneous measurement and optimization. &lt;a class="footnote-reference brackets" href="#id2" id="id1" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;1&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;ol class="arabic"&gt;
&lt;li&gt;&lt;p&gt;Run a timed test of application code with frame-by-frame measurements.&lt;/p&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;ol class="arabic simple"&gt;
&lt;li&gt;&lt;p&gt;At the beginning of each frame, start cProfiler.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;At the end of each frame, stop cProfiler and save the results for the
frame.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;At the end of each frame, log timing information from the frame for
later analysis.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Identify the exceptional frames. This is the set of frames for which the
frame’s performance is significantly worse than the frame preceding it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Select the worst exceptional frame from the session.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Perform the average optimization process described above, using the data
from the exceptional frame.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;section id="the-tools"&gt;
&lt;h2&gt;The Tools&lt;/h2&gt;
&lt;p&gt;I made some changes to the demo framework code to support this process.
Before beginning the engine update loop for the frame, the application code
starts the frame timer and the profiler. After the engine update loop ends, it
stops both. The application then sends timing information for the frame to the
statistics module. The statistics module logs a JSON event with the information
for the frame. This process repeats for each frame through the life of the
application.&lt;/p&gt;
&lt;p&gt;Here are examples of JSON events for 3 frames.&lt;/p&gt;
&lt;div class="highlight-text notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span/&gt;2018-05-21 12:30:53,295 - statistics - INFO - frame - {'frame_num': 0, 'time_start': 1526931053.2692273, 'time_end': 1526931053.2937021, 'ms_per_frame': 24.4748592376709, 'variation': 0, 'entity_count': 13}
2018-05-21 12:30:53,310 - statistics - INFO - frame - {'frame_num': 1, 'time_start': 1526931053.2955983, 'time_end': 1526931053.3093357, 'ms_per_frame': 13.73744010925293, 'variation': -0.43871219132044226, 'entity_count': 19}
2018-05-21 12:30:53,324 - statistics - INFO - frame - {'frame_num': 2, 'time_start': 1526931053.3101385, 'time_end': 1526931053.323486, 'ms_per_frame': 13.347625732421875, 'variation': -0.02837605650913761, 'entity_count': 25}
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;After finishing the application run, we have frame-by-frame profiler sessions
and timing statistics.  This is enough information to do both average and
instantaneous analysis for a session.&lt;/p&gt;
&lt;p&gt;I wrote tools in Python to visualize the data for analysis as follows:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;&lt;p&gt;Transform the JSON frame events into a &lt;a class="reference external" href="https://docs.scipy.org/doc/numpy/reference/generated/numpy.recarray.html"&gt;numpy recarray&lt;/a&gt;
for further processing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Print summary performance statistics from the run.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Identify exceptional frames.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For each exceptional frame,&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;&lt;p&gt;Process the frame’s profiler session through pyprof2calltree and
callgrind_annotate.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Print the costliest function from the frame.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use matplotlib to create statistical graphs.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;With repeatable process and tools ready, we can analyze real session data.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="the-data"&gt;
&lt;h2&gt;The Data&lt;/h2&gt;
&lt;p&gt;There following data are from a long session I ran after first noticing the
frame rate drops.  An exceptional frame in this analysis is defined as a frame
with a duration &amp;gt; 0.5 times that of the previous frame. Here are the summary
statistics.&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;Session start (sec): 1526931053.27&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Session end (sec): 1526933520.75&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Session length (sec): 2467.48&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;ms/frame (mean): 87.80&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;ms/frame (median): 79.32&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;ms/frame (std dev): 75.96&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Exceptional frames (variation multiple &amp;gt; 0.5): 96&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;sec/exceptional frame: 25.70&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;ms/frame (mean): 798.30&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;ms/frame (median): 278.32&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;ms/frame (std dev): 1029.25&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Active entities (mean): 206.07&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Active entities (median): 205.00&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Active entities (std dev): 17.90&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The data will be more useful when we compare it relative to later runs after
optimizing. It is still valuable on its own. Since I’ve qualitatively deemed
the frame rate unstable by watching it on my monitor, the data establish a
quantitative baseline for the same.&lt;/p&gt;
&lt;p&gt;Some quick observations.&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;Frame rate varies by up to 87% in only one standard deviation. In other
words, 68% of frames in this run are 87.80 +/- 75.96 ms/frame.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;On average, there is an exceptional frame (ms/frame &amp;gt;50% longer than the
frame before it) every 25.7 seconds.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;On average, each exceptional frame takes 9.09 times as long as each normal
one.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The following graph shows the times for each frame over the entirety of the
run.&lt;/p&gt;
&lt;figure class="align-default"&gt;
&lt;img alt="../_images/2018-05-25-frame_rate_runtime_1c66ba-start.png" src="../_images/2018-05-25-frame_rate_runtime_1c66ba-start.png"/&gt;
&lt;/figure&gt;
&lt;p&gt;Each of the spikes appears to be an exceptional frame. This visualization also
shows the severity of the exceptions worsening over time, which isn’t apparent
from the summary statistics. There are frame times over 4 seconds toward the
end of the run. The average frame rate seems mostly stable, although it looks a
little like it creeps upward after about 33 minutes.&lt;/p&gt;
&lt;p&gt;The following graph shows frame to frame variation. This is the duration of
each frame, relative to that of the previous frame.&lt;/p&gt;
&lt;figure class="align-default"&gt;
&lt;img alt="../_images/2018-05-25-frame_rate_variation_1c66ba-start.png" src="../_images/2018-05-25-frame_rate_variation_1c66ba-start.png"/&gt;
&lt;/figure&gt;
&lt;p&gt;Some frames take more than 40 times as long as their preceding frames!&lt;/p&gt;
&lt;p&gt;The following graph also shows frame to frame variation, but only for the
exceptional frames.&lt;/p&gt;
&lt;figure class="align-default"&gt;
&lt;img alt="../_images/2018-05-25-frame_rate_variation_exc_1c66ba-start.png" src="../_images/2018-05-25-frame_rate_variation_exc_1c66ba-start.png"/&gt;
&lt;/figure&gt;
&lt;p&gt;Unsurprisingly, the shape is the same of the previous graphs. The exceptions
get worse as the session lengthens.&lt;/p&gt;
&lt;p&gt;Finally, here are the most expensive functions for the 5 worst exceptional
frames, according to callgrind.&lt;/p&gt;
&lt;div class="highlight-text notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span/&gt;Frame  # ms/frame          call site

25798  4167.9699420928955  /usr/lib/python3.6/site-packages/ng/math/vector.py:__init__
27314  4120.220422744751   /usr/lib/python3.6/site-packages/ng/ng.py:_entities_velocity
24394  3972.6834297180176  /usr/lib/python3.6/site-packages/ng/math/matrix.py:__matmul_
21420  3672.304391860962   /usr/lib/python3.6/site-packages/ng/ng.py:_entities_velocity
20191  3374.32861328125    /usr/lib/python3.6/site-packages/ng/math/matrix.py:__init__
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This analysis shows the worst frame rate issues happen when using ng’s math
facilities.  &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;vector.py&lt;/span&gt;&lt;/code&gt; and &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;matrix.py&lt;/span&gt;&lt;/code&gt; are ng’s vector and matrix
classes. &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;ng.py:_entities_velocity&lt;/span&gt;&lt;/code&gt; is the function that updates each
entity’s position using its velocity vector.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="next"&gt;
&lt;h2&gt;Next?&lt;/h2&gt;
&lt;p&gt;Did I miss anything useful in the analysis above? If so, please let me know.&lt;/p&gt;
&lt;p&gt;Thanks for reading! Next time, we’ll review my progress optimizing the math
modules and resulting measurements.&lt;/p&gt;
&lt;aside class="footnote-list brackets"&gt;
&lt;aside class="footnote brackets" id="id2" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;&lt;a role="doc-backlink" href="#id1"&gt;1&lt;/a&gt;&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;Thanks to gcbirzan from freenode #python for the suggestion to do
frame-by-frame cProfiler measurements.&lt;/p&gt;
&lt;/aside&gt;
&lt;/aside&gt;
&lt;/section&gt;
</description><pubDate>Sat, 26 May 2018 00:00:00 </pubDate></item><item><title>Dev Log 2018-05-21</title><link>http://www.mahnke.tech/blog/2018-05-21-dev-log.html</link><description>

&lt;section id="entity-graph-completed"&gt;
&lt;h2&gt;Entity Graph Completed&lt;/h2&gt;
&lt;p&gt;Entity graphs/scene graphs with parent/child relationships and relative
transformations are now fully supported.&lt;/p&gt;
&lt;p&gt;I corrected errors in matrix multiplication order as well as storage format.
The second problem was difficult to find, only subtly becoming apparent when
entities changed display size along with their z position, which shouldn’t have
happened with the orthographic projection matrix I was using. Some people in
freenode ##OpenGL helped me narrow it down to transpose. As derhass said,
“matrix layout is like the USB A connector. you always get it wrong the first
round”.&lt;/p&gt;
&lt;p&gt;The storage format issue was ultimately a discrepancy between my matrix class
and &lt;a class="reference external" href="https://glm.g-truc.net/0.9.8/index.html"&gt;GLM&lt;/a&gt;’s, which I was mixing. My
matrices are stored row major, whereas GLM’s are stored column major.
Everything outside GLM was configured to expect row major, so multiplication
against GLM’s matrices was yielding the wrong result. I initially tried to
correct this with GLM’s transpose function, but this is what happened when I
tried it:&lt;/p&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span/&gt;&lt;span class="n"&gt;In&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;glm&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ortho&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;320.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;320.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;240.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;240.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;100.0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;In&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;
&lt;span class="n"&gt;Out&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
&lt;span class="n"&gt;tmat4x4&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;     &lt;span class="mf"&gt;0.003125&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;            &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;            &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;            &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;            &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="mf"&gt;0.00416667&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;            &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;            &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;            &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;            &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;        &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;0.02&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;            &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;           &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;           &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;           &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;            &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;In&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="n"&gt;glm&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transpose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;Out&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
&lt;span class="n"&gt;tmat4x4&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;     &lt;span class="mf"&gt;0.003125&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;            &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;            &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;           &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;            &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="mf"&gt;0.00416667&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="mf"&gt;0.00416667&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;           &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;            &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;            &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;        &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;0.02&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;           &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;            &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;            &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;            &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;            &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The extra 0.00416667 in [1][2] of the transpose is incorrect. I’m not sure if
this is an issue with GLM itself or &lt;a class="reference external" href="https://pypi.org/project/PyGLM/"&gt;PyGLM&lt;/a&gt;.
Since I only need simple view and projection matrices for now, I removed PyGLM
and am calculating them directly. I would like to be able to use PyGLM’s
features eventually, so I will try the same transpose experiment with the C GLM
library and isolate the error.&lt;/p&gt;
&lt;p&gt;Working through different matrix operations on paper and with IPython this week
has helped me to understand how to use a matrix to represent a system of linear
equations. I’ve also gotten a better understanding of how to use matrices as a
storage format for individual transformations that can be executed in series
using matrix multiplication.&lt;/p&gt;
&lt;p&gt;The entity graph is implemented by sending each entity’s vertices through a
series of transformation matrices: &lt;strong&gt;projection * view * parent * display *
translate * scale * rotate&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;With the entity graph completed, development on another important feature
begins.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="particle-systems-started"&gt;
&lt;h2&gt;Particle Systems Started&lt;/h2&gt;
&lt;p&gt;Particle systems can create many visual effects, and can also be a performance
indicator for a graphics engine. I wanted to see how well &lt;a class="reference external" href="2018-03-11-introducing-ng-engine.html"&gt;ng&lt;/a&gt; could do this in its current state,
so I started work on a simple particle system. Particles are created by an
emitter. An emitter is created as follows,&lt;/p&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span/&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;emitter0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_ng&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;emitter_create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'emitter0'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;delay_sec&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'star'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'position'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="mi"&gt;635&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;635&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;480&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="s1"&gt;'origin'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;'velocity'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;50.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;70&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="s1"&gt;'texture'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'star02'&lt;/span&gt;&lt;span class="p"&gt;}})&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;where &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;delay_sec&lt;/span&gt;&lt;/code&gt; is the delay in seconds between particles, and &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;template&lt;/span&gt;&lt;/code&gt;
is the entity creation template. The creation template is the blueprint the
emitter uses to create its particles. Note the two 3d values supplied for both
position and velocity. This syntax means each new particle entity will be
assigned a random value between the two values of these arguments. In
the above example, each particle created by the emitter is assigned a position
with a random y value between 0 and 480.&lt;/p&gt;
&lt;p&gt;I created a demo with a scrolling star field and ships with fuel trails to test
the emitters.&lt;/p&gt;
&lt;figure class="align-default" id="id1"&gt;
&lt;img alt="../_images/2018-05-20_demo_emitter.gif" src="../_images/2018-05-20_demo_emitter.gif"/&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;In this demo, every star and fuel trail is created by an emitter.&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;These initial emitters simply create many entities on a delay, so a particle
created by an emitter has the same properties as any other entity created by
the engine. I don’t yet know if this pattern can scale to thousands or more
particles. This will become clear in the next days and weeks, both as I finish
more rounds of performance optimization, and as I learn more about the
relationships between CPU, GPU, and OpenGL object model with respect to overall
performance.&lt;/p&gt;
&lt;p&gt;Serendipitously, implementing the initial particle system this way has been an
excellent first performance test. Emitters are a great way to test frequently
creating and destroying a large number of entities and examine the effects on frame
rate under these conditions.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="performance-optimizations"&gt;
&lt;h2&gt;Performance Optimizations&lt;/h2&gt;
&lt;p&gt;As initially configured, the new demo keeps a few hundred entities on display
at once with particle emitters. The first time I ran the demo, it highlighted
performance issues. Frame completion times quickly exceeded 80-100
milliseconds/frame. These issues haven’t been noticeable with previous demos,
which are simple feature tests using only a small number (&amp;lt; 10) of simultaneous
entities.&lt;/p&gt;
&lt;p&gt;I used the &lt;a class="reference external" href="https://docs.python.org/3/library/profile.html"&gt;cProfiler&lt;/a&gt; module
to profile some runs of the demo. Then, I used the &lt;a class="reference external" href="https://pypi.org/project/snakeviz/"&gt;snakeviz&lt;/a&gt; module to visualize the results. This
was the first time profiling the engine, so I wasn’t surprised to see many
functions with cumulative run time higher than expected. I went through the
worst offending functions with &lt;a class="reference external" href="https://pypi.org/project/line_profiler/"&gt;line_profiler&lt;/a&gt; to find the costliest and easiest
to optimize operations. After each change, I repeated the profiling, analysis,
and optimization process, gradually improving performance.&lt;/p&gt;
&lt;p&gt;There were several easy optimizations. Some of these were issues I’d already
anticipated; I’d written simple, but potentially problematic code, mentally
noted it as such, and moved on. Others were surprises.&lt;/p&gt;
&lt;section id="mesh-vbo-optimization"&gt;
&lt;h3&gt;Mesh VBO Optimization&lt;/h3&gt;
&lt;p&gt;The GL renderer was updating the VBO for each entity mesh every frame. The
optimization is to only update the VBO when the vertices actually change. This
happens only when the entity size or origin changes. On one of these changes,
the entity now fires an ENTITY_MODEL_INIT event. The GL renderer updates the VBO
for an entity only in response to this event.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="uv-vbo-optimization"&gt;
&lt;h3&gt;UV VBO Optimization&lt;/h3&gt;
&lt;p&gt;The GL renderer was updating the VBO for texture coordinates every frame. The
optimization is to only update the VBO when texture coordinates change. This
happens only when the entity’s texture or animation frame changes. The renderer
now stores the UV coordinates in the VBO in main memory, as well.  When the
texture or animation frame changes, it compares the new coordinates to the
in-memory ones. If they differ, it updates the VBO with the new coordinates.
Rather than using this state polling loop, I’d prefer to handle this update
using an event handler as described in the mesh optimization above. The
requisite TEXTURE_CHANGE event isn’t available yet, so I plan to refactor this
later after adding it.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="cache-shader-uniform-locations"&gt;
&lt;h3&gt;Cache Shader Uniform Locations&lt;/h3&gt;
&lt;p&gt;The GL renderer was calling &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;glGetUniformLocation&lt;/span&gt;&lt;/code&gt; to get uniform locations
every frame. This call is expensive and the returned value is valid for the
lifetime of the shader program. The optimization is to store uniform locations
in main memory after linking the shader, and use the cached locations as needed
instead of calling &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;glGetUniformLocation&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="fewer-matrix-operations"&gt;
&lt;h3&gt;Fewer Matrix Operations&lt;/h3&gt;
&lt;p&gt;ng’s current patterns of creating and multiplying matrices are expensive (more
on this in the next post). One way to mitigate this is to do less of it.&lt;/p&gt;
&lt;p&gt;The entity update routine was recalculating every transformation matrix
(rotate, scale, and translate) as well as the model matrix each time any of
local space properties changed. The optimization is to change only what is
necessary. For example, if the user updates the entity’s position, only
recalculate the translate matrix and the model matrix.&lt;/p&gt;
&lt;p&gt;I think there are still opportunities to reduce the number of matrix operations
each frame, and will come back to this.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="improvement"&gt;
&lt;h3&gt;Improvement&lt;/h3&gt;
&lt;p&gt;After these and few other changes, the emitter demo runs at &amp;lt;50 ms/f on my
development system. There is a lot more to do for performance, and I’m looking
forward to doing more optimizations over the next few days.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="next"&gt;
&lt;h2&gt;Next?&lt;/h2&gt;
&lt;p&gt;I would like to create a side scrolling space shooter in June. With the entity
graph and particle system features complete, the major features required for
this are there.&lt;/p&gt;
&lt;p&gt;The question is around performance. My hunch guess is that what I have in
mind would run at an average 80-100 ms/f in the current version of ng, where I
would prefer it to be less than 35 ms/f. In addition to concerns around
average frame rate, there are also intermittent frame rate drops in the emitter
demo. Every few seconds, the time between two frames doubles, creating a visual
jerk before recovering to the average frame rate.&lt;/p&gt;
&lt;p&gt;It’s become clear to me that performance tuning will be an ongoing activity.
This week, I’ll develop tools to analyze average and instantaneous frame rate
issues and see how much I can do to improve. We’ll re-evaluate the results and
see if we can start making a side scrolling shooter in June.&lt;/p&gt;
&lt;/section&gt;
</description><pubDate>Mon, 21 May 2018 00:00:00 </pubDate></item><item><title>Dev Log 2018-05-14</title><link>http://www.mahnke.tech/blog/2018-05-14-dev-log.html</link><description>

&lt;section id="opengl-renderer-finished"&gt;
&lt;h2&gt;OpenGL Renderer Finished&lt;/h2&gt;
&lt;p&gt;I’ve been working almost exclusively on the OpenGL code in a branch.  I reached
feature parity between the OpenGL and SDL renderers. I merged that code line to
the main one, since GL is now pretty stable and upcoming work will be easier to
do on the main branch. There are minor issues to fix.&lt;/p&gt;
&lt;p&gt;Fonts are currently rendered to a texture at the user-specified size in pixels.
If the logical resolution is different than the display resolution, those
textures are scaled (usually upscaled) to the size of the logical resolution
for drawing. This doesn’t look good for anti-aliased fonts, so I’ll need to
decide how to improve it.&lt;/p&gt;
&lt;p&gt;When using draw-to-texture in GL, the y axis and texture winding directions for
drawing seem to be inverted vs. drawing directly to display. I’m confused by
this, but decided to move on and come back to revisit it later, when I
understand GL better. It may be best diagnosed by creating the smallest
possible example application to reproduce the behavior.&lt;/p&gt;
&lt;p&gt;The SDL renderer handled everything in display coordinates. Rendering in GL
required an additional transformation to normalized device coordinates, which
the SDL renderer doesn’t understand. These changes left the SDL renderer a
little broken. The next work is a documentation and refactoring effort around
the coordinate transformations.  If that goes well, I expect SDL to be fixed
easily. In the worst case, I’ll leave SDL behind for now and come back to fix
it later; GL is the priority now.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="better-development-workflow"&gt;
&lt;h2&gt;Better Development Workflow&lt;/h2&gt;
&lt;p&gt;I have a few demo applications that have been in the same git repository as the
ng engine code. These exercise ng’s features and I use them to verify
that code changes haven’t broken things. I frequently make small changes to
these to test little ideas, and a problem I’ve been facing is they are
consistently in a modified state, making it difficult to switch between code
branches without committing/stashing/discarding the changes.&lt;/p&gt;
&lt;p&gt;Since I’m compelled to commit changes to the demos less frequently than changes
to the engine, I decided the best solution for now is to move the demos to
their own repository so they don’t interfere with the engine development
workflow.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="better-demos"&gt;
&lt;h2&gt;Better Demos&lt;/h2&gt;
&lt;p&gt;The demos mentioned above started as freestanding applications without any
shared code. Changes to ng APIs have required changes to every demo
application. This has become a maintenance issue as the amount of time it takes
to update the applications grows with the number of applications.&lt;/p&gt;
&lt;p&gt;To improve this, I created a base application class that creates contexts for
ng and shared utilities like resolution changing, debug grid and drawing
performance statistics. Now each new demo can inherit from this base class.
Changes to ng APIs will, best case, only require changes to the base
application class.&lt;/p&gt;
&lt;figure class="align-default" id="id1"&gt;
&lt;img alt="../_images/2018-05-14_demo_entity_graph.gif" src="../_images/2018-05-14_demo_entity_graph.gif"/&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;This is the demo application for the entity graph.&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/section&gt;
&lt;section id="next"&gt;
&lt;h2&gt;Next?&lt;/h2&gt;
&lt;p&gt;The next priority is to ensure there’s a well-defined, well-documented path
between the user’s input coordinate frame and the final display coordinate
frame. This “works” in most 2D use cases right now, but there is some
stretching in non-square resolutions and probably other subtle issues.&lt;/p&gt;
&lt;p&gt;Entity graphs (work in progress), support for cameras and camera
transformations (short-term future work), and full 3D rendering (mid- to long-term
future work) all depend on this part of the engine being correct.&lt;/p&gt;
&lt;p&gt;I think there are some errors in the matrices and their concatenations, so I’ll
start by building some test cases around that. Debugging here is a bit
challenging since the final transformation of model space vertex coordinates to
display coordinates happens in the shader; there’s no way to test the entire
pipeline, including OpenGL, in the Python code. I plan to create some test
cases or an application that only does the math and verifies the correctness of
the results, with no need for GL or drawing on the display.&lt;/p&gt;
&lt;p&gt;Thanks for reading. I’m looking forward to the next update.&lt;/p&gt;
&lt;/section&gt;
</description><pubDate>Mon, 14 May 2018 00:00:00 </pubDate></item><item><title>Dev Log 2018-05-09</title><link>http://www.mahnke.tech/blog/2018-05-09-dev-log.html</link><description>

&lt;p&gt;Multi-line text in text area gadgets is now completed. Getting the line height
and spacing correct was a bit trickier than expected. This may partially be my
misunderstanding how FreeType’s data should be used. FreeType recommends a
baseline-to-baseline line spacing, but this was smaller than the sum of
ascender and descender distance in my test fonts, which seems like an error on
the font’s part. I work around it by using either the height recommendation or
the ascender + descender distance, whichever is larger.&lt;/p&gt;
&lt;p&gt;I moved debug grid drawing code out of ng’s renderer, placing that burden on
the user’s code instead. The debug grid shows evenly spaced lines on the x and
y axis. This is extremely useful for verifying things are the correct size and
location; I’m just not sure it belongs in the core renderer. Since the user can
hook the RENDER_CLEAR event and do whatever they want with the context, I’ll
let user code handle it for now.&lt;/p&gt;
&lt;figure class="align-default" id="id1"&gt;
&lt;img alt="../_images/2018-05-09_debug_grid.png" src="../_images/2018-05-09_debug_grid.png"/&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;Debug grid&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Drawing the borders around nui gadgets is completed. This is done by drawing
the border to a texture in the nui rendering pass, then drawing the texture to
the display in the ng pass as usual. I tried drawing the border with drawing
mode GL_LINE_LOOP, but that didn’t work as expected, seemingly adding an
unwanted vertex at the origin (center) of the texture. GL_LINES gives a
satisfactory result for now, but causes some visible disconnected pixels at the
junctions between lines, so I’ll need to revisit later and figure out what I’m
doing wrong with GL_LINE_LOOP.&lt;/p&gt;
&lt;p&gt;I cleaned up the drawing paths significantly, so now all entities are using the
same VBO model and vertex layout.&lt;/p&gt;
&lt;p&gt;I installed &lt;a class="reference external" href="http://awstats.org"&gt;awstats&lt;/a&gt; on this site to get more information
about who might be reading.&lt;/p&gt;
</description><pubDate>Wed, 09 May 2018 00:00:00 </pubDate></item><item><title>Dev Log 2018-05-05</title><link>http://www.mahnke.tech/blog/2018-05-05-dev-log.html</link><description>

&lt;p&gt;Entity graph tests are partially passing, but there are issues at non-square
resolutions and with certain entity origins. I know the model/view/projection
matrix calculations aren’t quite right, so that’s the place to start
investigating. It’s on the back burner while I work through fundamental design
for the OpenGL renderer.&lt;/p&gt;
&lt;p&gt;The new renderer is already able to draw quite a bit of what the SDL renderer
does. This includes textured entities with local transformations, debug OOBB
and AABB, and single-line text strings.&lt;/p&gt;
&lt;p&gt;Text rendering is more complex with OpenGL than SDL. The SDL_ttf extension
provides a convenient TTF string to texture functionality. For OpenGL, I use
FreeType to load the data for the desired string and font.  FreeType provides
the information required to determine the dimensions of the texture on which to
draw the text, as well as the information required to place the bitmaps for the
individual characters vertically and horizontally on that texture.&lt;/p&gt;
&lt;figure class="align-default" id="id1"&gt;
&lt;img alt="../_images/freetype_glyph_metrics.png" src="../_images/freetype_glyph_metrics.png"/&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;FreeType horizontal glyph metrics&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;FreeType provides the bearing, which is the distance between the top of a glyph
and the baseline of a line of text.  Everything is relative to the baseline.
For a one line texture, the total height needs to be at least the sum of the
largest distance between the baseline and the top of a glyph and the largest
distance between the baseline and bottom of a glyph, for all the glyphs used in
the string.  I calculate the texture height, then find the texture y offset for
the baseline. Finally, I position each letter relative to the baseline.&lt;/p&gt;
&lt;p&gt;I draw characters to a texture and update vertex data in the nui rendering
pass, then ng renders those entities with the textures in the usual way.&lt;/p&gt;
&lt;p&gt;The next steps for text are to make sure different types and styles of fonts
are working, and then to support multi-line strings. This should be
straightforward.  FreeType font data provides the info to calculate baseline to
baseline distance, so I should be able to extend the above algorithm to create
a texture for multiple lines of text.&lt;/p&gt;
&lt;p&gt;The OpenGL renderer currently allocates a VAO and multiple VBOs for each
instance of an entity. This is not the efficient way to do things, but it was
the shortest path from OpenGL tutorials to desired functionality. Normal
textured entities have a VAO, a VBO for the model vertices, a VBO for UV
coordinates, and a VBO for AABB vertices. Text entities have a VAO and one
shared VBO for both model vertices and UV coordinates, since I currently use a
static depth for text (tutorial stuff) and send both model vertices and UV
coordinates to the shader using one vec4 vertex attribute. There are two
different rendering paths to handle the different setups. Those will be
consolidated as I work through the use cases and develop a better understanding
of OpenGL state and the relationships between VAO, VBO, and shaders.&lt;/p&gt;
</description><pubDate>Sat, 05 May 2018 00:00:00 </pubDate></item><item><title>Reanimated Refuse (One Game a Month, April)</title><link>http://www.mahnke.tech/blog/2018-05-03-ogam-april-reanimated-refuse.html</link><description>

&lt;p&gt;&lt;em&gt;Published on 2018-05-03.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I was first informed about the perils of waste disposal in early grade school.
I remember going to the gym with the rest of the school (they called it an
“assembly”) where a group of adults gave a presentation urging us to put glass
and plastic into a different container.  The reasoning, as I remember it, was
that we would run out of space in landfills to put things if we didn’t recycle
them instead. We must have been convinced; I remember us all chanting “REDUCE,
REUSE, RECYCLE!” in unison with the presenters.&lt;/p&gt;
&lt;p&gt;These days, I would ask more questions.&lt;/p&gt;
&lt;p&gt;The United States is decidedly not running out of places to put our garbage in
a way that creates a sense of urgency.  Since the 1970s, the country has moved
from a large number of small, low-tech municipal hole-in-the-ground dumps to a
small number of more highly-engineered landfill sites.  Long-term waste
management seems like an interesting engineering challenge. The organic waste
component of a landfill gives it some properties of an enormous compost pile.
We can separate the methane gas and use it for energy. The harmful leachate
runoff from liquid waste is now caught in liners that are installed in all
landfills, so it doesn’t contaminate the ground.&lt;/p&gt;
&lt;p&gt;Though I’m satisfied I won’t be living in piles of trash anytime in my next few
lifetimes, there’s more to the issue than space. The trend toward a small
number of large, strategically placed landfill sites increases the likelihood
of regional issues. Since the closest landfill is farther away than the “town
dump” was, cities must manage their temporary capacity more carefully.
Regional refuse must be transported to a landfill, which contributes to carbon
dioxide emissions. Where does all that toxic leachate go, that isn’t as bad as
putting it in the ground?&lt;/p&gt;
&lt;p&gt;I just wanted to know how guilty I should be when I throw things in the trash,
but things get complicated quickly.  I don’t think it’s controversial to
suggest our best bet is to avoid putting non-biodegradable stuff into holes
when there’s no reason to do so.  On the other hand, looks like we’re putting
talented engineering resources into landfill technology and can accept the cost
of storing something that had a net positive, albeit temporary, effect on the
owner’s life.&lt;/p&gt;
&lt;section id="the-project"&gt;
&lt;h2&gt;The Project&lt;/h2&gt;
&lt;p&gt;April’s creation for &lt;a class="reference internal" href="2018-03-08-one-game-a-month.html"&gt;&lt;span class="doc"&gt;OGAM&lt;/span&gt;&lt;/a&gt; is called
Reanimated Refuse.  This game is about unchecked waste disposal bringing
consequences in a more immediate way than environmental destruction. No longer
satisfied being relegated to landfills, garbage wants to bury the world. Only
you, the mild-mannered, journeyman waste collector, can stop the onslaught.&lt;/p&gt;
&lt;p&gt;A first for April is a title screen, which gave it a more complete feel for me.
I will try to do this for every game going forward.&lt;/p&gt;
&lt;img alt="../_images/2018-05-02_title.png" src="../_images/2018-05-02_title.png"/&gt;
&lt;p&gt;RR is a wave-based, fixed shooter with mechanics similar to Space Invaders and
Galaga. The collector must avoid being hit while shooting through multiple
missions, each with progressively more challenging waves of garbage.  Cut from
the original idea was side scrolling (a good call). This is because ng doesn’t
have support for moving cameras yet.&lt;/p&gt;
&lt;p&gt;Here’s an animation showing the gameplay.&lt;/p&gt;
&lt;figure class="align-default" id="id1"&gt;
&lt;img alt="../_images/2018-05-02_gameplay.gif" src="../_images/2018-05-02_gameplay.gif"/&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;The best development moment of the month was the first time I watched the spinning
six pack ring come down and take the collector out.&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;While this is another minimalist effort, I’m satisfied with the completeness of
its gameplay and graphics. RR also struck a good balance of reusing existing
features (frame animation, tile map support, text rendering) with new features
for April (nui improvements, texture rotation and scaling, mouse support and
picking).&lt;/p&gt;
&lt;/section&gt;
&lt;section id="the-tech"&gt;
&lt;h2&gt;The Tech&lt;/h2&gt;
&lt;p&gt;&lt;a class="reference internal" href="2018-03-11-introducing-ng-engine.html"&gt;&lt;span class="doc"&gt;ng&lt;/span&gt;&lt;/a&gt; received a few major features in
March, but the biggest were frame animation and texture atlas support. April’s
major feature is nui rendering improvements.  There is also a lot of
under-the-hood work done to support the entity graph feature, which will be
finished in early May.&lt;/p&gt;
&lt;p&gt;I’ve done a lot of light refactoring – reorganizing modules, renaming,
improving logging – to make things easier to understand for my present and
future self.&lt;/p&gt;
&lt;p&gt;Here’s the ng diff since the last update:&lt;/p&gt;
&lt;div class="highlight-text notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span/&gt;diff --git a/doc/plan/plan.rst b/doc/plan/plan.rst
index 4e23e3e..d60752d 100644
--- a/doc/plan/plan.rst
+++ b/doc/plan/plan.rst
@@ -1,14 +1,10 @@
 To do
 =====

-- Fix pick functionality when device-independent resolution doesn't
-  match actual window size.
-- Reusable logging configuration for each module.
+- Add camera system to support scrolling playfields.
 - Support multiplicative color modification of entities.
-- Add collision info to event system.
 - Implement Python configuration DSL.
 - Add/remove debug and performance statistics with 'z' key.
-- Support center point (pivot point) for rotation.
 - Simple IPython integration.
 - Annotation-based profiler.
 - Add copyright/licensing info to files on build.
@@ -16,6 +12,59 @@ To do
 Finished
 ========

+2018-04-19
+----------
+
+- Reusable logging configuration for each module.
+
+2018-04-18
+----------
+
+- Make nui use ng to do its rendering, instead of using an independent
+  rendering step.
+
+  - Separate ng local texture rendering step from output rendering.
+  - Make nui also do local rendering to textures.
+  - Make ng do final output rendering of nui gadgets.
+
+2018-04-13
+----------
+
+- Support nui font customization.
+- Change picking and collision detection to use world AABB instead of primitive
+  texture box.
+
+2018-04-10
+----------
+
+- When objects collide, dispatch a collision event with information about the
+  pair.
+- Implement vector length, normalize, and scalar multiplication operations.
+- Add support for mouse button clicks. Send button up/down events.
+
+2018-04-09
+----------
+
+- Fix pick functionality when device-independent resolution doesn't
+  match actual window size.
+
+2018-04-05
+----------
+
+- Support center point (pivot point) for rotation.
+- Implement entity graph (parent/child relationships).
+
+2018-04-01
+----------
+
+- Send an event after renderer is cleared, so the caller can hook.
+
+2018-03-26
+----------
+
+- Support non-animated entity loading from Aseprite JSON format.
+- Support animation loading from Aseprite JSON format.
+
 2018-03-21
 ----------
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Let’s look at some highlights for the development month of April.&lt;/p&gt;
&lt;section id="entity-graph"&gt;
&lt;h3&gt;Entity Graph&lt;/h3&gt;
&lt;p&gt;Also known as a &lt;a class="reference external" href="http://archive.gamedev.net/archive/reference/programming/features/scenegraph/index.html"&gt;scene graph&lt;/a&gt;,
the entity graph allows entities to be transformed relative to one another, in
addition to being transformed relative to the world. This feature is a work in
progress, so it will be covered in depth in a future update.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="nui"&gt;
&lt;h3&gt;nui&lt;/h3&gt;
&lt;p&gt;During very early prototyping for ng, I made a simple user interface module
called nui, which rendered text boxes and bordered windows. All text drawn in
all screenshots on this blog use nui.&lt;/p&gt;
&lt;p&gt;nui originally rendered its user interface elements (called “gadgets”) in its
own rendering pass, so everything nui did was rendered after/on top of
everything ng does. This became problematic in two ways. First, separate
rendering passes meant no way to layer ng/nui entities.  For example, placing a
spinning cursor using ng’s animation system on top of a nui window would have
been impossible.  Secondly, nui entities had no way to participate in the
simulation of the game world. Since they were drawn statically, they couldn’t
easily move, rotate, disappear automatically after a time, and so on.&lt;/p&gt;
&lt;p&gt;To improve this, I made some changes in the way nui and ng work together.
First, gadgets now inherit from ng entities, so they can take advantage of all
the functionality provided by entities.  Secondly, nui now renders the graphics
for its gadgets to textures instead of to the display.  These textures are
associated with the gadget entities before display rendering starts. Finally,
all entities, including gadgets, are now rendered by ng to the display in a
single pass.&lt;/p&gt;
&lt;p&gt;These changes resolve the issues described above, and also resolve the burden
of maintaining two different display rendering routines into the future.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="mouse-cursor"&gt;
&lt;h3&gt;Mouse Cursor&lt;/h3&gt;
&lt;p&gt;There’s now support for getting the position of the mouse cursor within the
game window, either in terms of the output resolution or the &lt;a class="reference internal" href="2018-03-23-ogam-march-cats-2.html#ogam-march-cats-2-logical-resolution"&gt;&lt;span class="std std-ref"&gt;logical
resolution&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The crosshair in the gameplay screenshot above is a normal entity. It follows
the mouse cursor location by setting its position to that of the mouse cursor
every frame.&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span/&gt;&lt;span class="n"&gt;mouse_pos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_ng&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mouse_pos&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_crosshair&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mouse_pos&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;
&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_crosshair&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mouse_pos&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="picking"&gt;
&lt;h3&gt;Picking&lt;/h3&gt;
&lt;p&gt;“Picking” is now supported. Picking is identifying the entitie(s) at a specific
display location, usually that of a cursor.&lt;/p&gt;
&lt;p&gt;Targeting and shooting the six pack rings in the screenshot is done by picking.
When the player clicks the mouse button, any entities under the cursor location
are picked. If this list contains  a hostile entity, it is destroyed and the
player’s score is increased.&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span/&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MOUSE_BUTTON_DOWN&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_input_enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'button'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;MouseButton&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LEFT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;picked&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_ng&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;entity_pick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_ng&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mouse_pos&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;picked&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;enemy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_get_enemy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;picked&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;enemy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="n"&gt;enemy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;die&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_entities&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;enemy&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_score&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="bounding-box-improvements"&gt;
&lt;h3&gt;Bounding Box Improvements&lt;/h3&gt;
&lt;p&gt;Both picking and collision handling routines use an entity’s world axis-aligned
bounding box (AABB). Picking works by testing to see if the location represented
by the mouse cursor is inside an entity’s AABB. &lt;a class="reference external" href="https://developer.mozilla.org/en-US/docs/Games/Techniques/3D_collision_detection"&gt;Collision detection&lt;/a&gt;
works by doing an intersection test between two entity’s AABBs; if the boxes
intersect, a collision is registered.&lt;/p&gt;
&lt;p&gt;ng’s first quick-and-dirty bounding box implementation was calculated by
multiplying an entity’s texture size by its scale. This broke when support for
rotation was added. For example, the AABB of a rectangular object that is wider
than it is long needs to grow in height and shrink in width as the object
rotates around its origin.&lt;/p&gt;
&lt;p&gt;AABB calculation now correctly respects all local transformations, allowing for
proper rendering, picking, and collision detection of entities in any
transformation state.&lt;/p&gt;
&lt;p&gt;When the six pack ring hits the garbage collector, this causes
their AABBs to pass the intersection test and a collision event to be sent.
The game code handles this collision event and uses it to kill the unfortunate
garbage collector.&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span/&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;COLLISION_CONTACT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_collector&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;life_state&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;LifeState&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DEAD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_collector&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'entities'&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_input_enabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_collector&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;die&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_respawn_timer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="per-module-logging-configuration"&gt;
&lt;h3&gt;Per-module Logging Configuration&lt;/h3&gt;
&lt;p&gt;ng provides a logger for each of its modules (main, rendering, and so on).
Initially, these loggers were initialized with a default log level that
couldn’t be changed publicly from game code, but only from inside ng’s source code.
There’s now a public interface to adjust logging per module. So, in
configuration:&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span/&gt;&lt;span class="n"&gt;LOGGING&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s1"&gt;'ng.collide'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'error'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'ng.event'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'error'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'ng.ng'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'error'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'ng.render.sdl'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'info'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'ng.sdl2'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'error'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'ng.timer'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'error'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'nui.nui'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'error'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'nui.render.sdl'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'info'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;And then in code:&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span/&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;config&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;level&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LOGGING&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;ng&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_level&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="in-conclusion"&gt;
&lt;h2&gt;In Conclusion&lt;/h2&gt;
&lt;p&gt;April has been a satisfying month. In addition to creating a fun little game, I
made progress on critical engine features and a lot of small improvements that
will pay off over time.&lt;/p&gt;
&lt;p&gt;May will be another major month for engine features. I’m excited to finish the
entity graph. I’ve also become more interested in &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Shader"&gt;shader&lt;/a&gt; programming while studying graphics
over the past few weeks. ng’s current renderer uses SDL, which doesn’t support
programmable shaders. For this reason, I’ve decided to add an OpenGL renderer
to ng. This will be finished in May and will complement the existing SDL
renderer for now, although it will probably ultimately replace it.&lt;/p&gt;
&lt;p&gt;Since the OpenGL renderer is a major change and I don’t have prior experience
using OpenGL, I’ve decided to focus on it, and not to do a game for May.
If things go smoothly, I’ll produce some technical demos using the new renderer
as it develops.&lt;/p&gt;
&lt;p&gt;Thanks for reading. Next time, we’ll review the progress of the entity graph and
the OpenGL renderer.&lt;/p&gt;
&lt;/section&gt;
</description><pubDate>Thu, 03 May 2018 00:00:00 </pubDate></item><item><title>One Game a Month, March Retrospective</title><link>http://www.mahnke.tech/blog/2018-04-04-ogam-march-retrospective.html</link><description>

&lt;p&gt;&lt;em&gt;Published on 2018-04-04.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;One of the things that can make starting a personal project feel so safe and
pure, compared to a project commissioned by a client or employer, is the
absence of deliverables and a deadline attached to them. “Do whatever you want”
as a set of requirements has an attractive mystique to it.&lt;/p&gt;
&lt;p&gt;One Game a Month’s &lt;a class="reference external" href="http://onegameamonth.com/faq"&gt;rules&lt;/a&gt; are left mostly open
to interpretation. In my interpretation, the only additional requirement over
the “do whatever you want” requirement set is “do it in one month.” OGAM is
about delivering a cohesive product each month. That one detail is enough to
make it a much different experience than a completely open-ended undertaking.&lt;/p&gt;
&lt;p&gt;Ending a project with a self-imposed deadline has been uncomfortable,
especially with one eye on the next idea on the horizon, carrying its own short
window of opportunity.  Writing this retrospective post feels equally
uncomfortable, but is obligatory.&lt;/p&gt;
&lt;p&gt;March has come to an end, and development on Cats is finished, for now.  Cats
is a very simple experience. As the observer of the story, you feed two cats
from your inventory. If you feed them regularly, they stay alive. If you
don’t feed them, they eventually die from weight loss and the game is over.&lt;/p&gt;
&lt;p&gt;And that’s about all there is to say about it. This is not a good, interesting,
or deep game.  It is a failure by many objective measurements.&lt;/p&gt;
&lt;p&gt;This work sacrificed on its own promise in order to drive efforts that will
benefit its successors. I am proud of it.&lt;/p&gt;
&lt;p&gt;Cats has a lot of amateur pixel art that indicates I am getting more
comfortable making amateur pixel art. I learned a lot about the fundamentals of
lighting, shading, and the use of color palettes.  These fundamentals will make
it easier and faster to create art for upcoming games.&lt;/p&gt;
&lt;p&gt;In lieu of compelling gameplay, we have several major engine features
implemented: a functional asset pipeline, entity graphs, animation, sound, tile
map rendering, and collision detection. All these things are available for use
in future projects.&lt;/p&gt;
&lt;p&gt;The bad side of March is that, while we have a running program with a core
mechanic, there is very little of a game around it. There’s not much fun to be
had this time.&lt;/p&gt;
&lt;p&gt;I spent some time thinking about it and understand how this happened. I started
with a mechanic that wasn’t fully developed, trusting it would evolve into
something interesting. It did, but the end result was too big in scope for the
time allotted, so I bailed on mechanics and worked on extracurricular fancy
instead; I spent the last couple days of the month developing new features for
the ng engine that I know I need for the April game.&lt;/p&gt;
&lt;figure class="align-default" id="id1"&gt;
&lt;img alt="../_images/2018-04-04_entity_graph.gif" src="../_images/2018-04-04_entity_graph.gif"/&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;I just do.&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;This was the correct decision. Assuming my game development skills improve with
each passing month, it’s more beneficial to set up for success in the next
month than to cram more development in for the current month’s entry. With that
in mind, it’s important to hit the right balance, so the next thing doesn’t
always cannibalize time from the project in progress.&lt;/p&gt;
&lt;p&gt;The lesson learned is to pull back ruthlessly on scope, and not rely on
emerging gameplay to guide feature development.&lt;/p&gt;
&lt;p&gt;Taking this lesson from March, I’m setting a new guideline for April: the game
should be playable with the mechanics fundamentally complete by the mid-month
halfway point.  This leaves 50% time to do refinements and to add features, or
to call it done early and move on.&lt;/p&gt;
&lt;p&gt;I’ll try this change for one month and evaluate again in the next
retrospective.&lt;/p&gt;
&lt;p&gt;While March feels like it’s been more of a practice session or warm up than a
performance, I’m excited to build on both the new tech and the new skills to
create something better in April.&lt;/p&gt;
&lt;p&gt;Thanks for reading. Next time, we’ll look at the April game!&lt;/p&gt;
</description><pubDate>Wed, 04 Apr 2018 00:00:00 </pubDate></item><item><title>Cats update 2 (One Game a Month, March)</title><link>http://www.mahnke.tech/blog/2018-03-23-ogam-march-cats-2.html</link><description>

&lt;p&gt;&lt;em&gt;Published on 2018-03-23.&lt;/em&gt;&lt;/p&gt;
&lt;section id="the-project"&gt;
&lt;h2&gt;The Project&lt;/h2&gt;
&lt;p&gt;It’s getting close to the end for OGAM March, and it’s time to talk more about
game engines and Cats.&lt;/p&gt;
&lt;p&gt;Things have taken a different direction since the last update. I
spent a lot of time drawing objects for the main house scene, to
give things a cozier feel. I also spent a lot of time making my workflow
and ng more stable.&lt;/p&gt;
&lt;section id="new-graphics"&gt;
&lt;span id="id1"/&gt;&lt;h3&gt;New Graphics&lt;/h3&gt;
&lt;p&gt;Here’s the new look:&lt;/p&gt;
&lt;img alt="../_images/2018-03-22_house.png" src="../_images/2018-03-22_house.png"/&gt;
&lt;p&gt;My drawing skills have always been poor, and I’m making an effort to improve.
I discovered &lt;a class="reference external" href="https://twitter.com/Pixel_Dailies"&gt;Pixel Dailies&lt;/a&gt; a few days
ago and have been participating each day, even if what I make isn’t good enough to
submit. I also placed some constraints on the art, which make it easier to
get pieces finished (less decision-making):&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;3/4 top down (JRPG) perspective.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;16x16 base tile size.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;16 color palette (&lt;a class="reference external" href="https://lospec.com/palette-list/dinoknight-16"&gt;DINOKNIGHT 16&lt;/a&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here’s the full diff for the Cats plan file since the last post:&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span/&gt; doc/plan/plan.rst | 36 +++++++++++++++++++++++-------------
 1 file changed, 23 insertions(+), 13 deletions(-)

diff --git a/doc/plan/plan.rst b/doc/plan/plan.rst
index 1e48dfc..19821ef 100644
--- a/doc/plan/plan.rst
+++ b/doc/plan/plan.rst
@@ -21,32 +21,42 @@ To do
 Future/maybe
 ------------

-- Communicate changes to user with a popup or scrolling marquee.
 - Cat is more/less likely to eat food based on preference.
 - Food degrades/spoils over time?
 - Some food is turned into waste and cats poop.
+- Add pause functionality.

-2018-03-28 milestone
---------------------
+OGAM deadline
+-------------

 - Support metric units.
-
-2018-03-21 milestone
---------------------
-
-- Add save/load game state functionality.
+- Implement hand as cursor.
 - Add breeds.
+- Make cats spawn in a random (and unoccupied) area in the house.
+- Feeding places food in bowl for cat to eat.
+- Add save/load game state functionality.
 - Bug: death animations are visible from other scenes.
 - View legacy of passed cats.

-2018-03-14 milestone
---------------------
-
-- Add pause functionality.
-
 Finished
 ========

+2018-03-21
+----------
+- Fix lockup.
+- Fix highlighting in select box so user can see selected item.
+
+2018-03-16
+----------
+
+- Support multilayer tiled maps.
+
+2018-03-14
+----------
+
+- Hovering over cat shows its statistics in floating gadget.
+- Bug: Feeding window does not show all food inventory.
+
 2018-03-10
 ----------
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="multilayer-maps"&gt;
&lt;h3&gt;Multilayer Maps&lt;/h3&gt;
&lt;p&gt;Support for multilayer maps allows us to put objects on top of the floor and
walls. It makes a big visual difference!&lt;/p&gt;
&lt;/section&gt;
&lt;section id="gameplay-and-interface-changes"&gt;
&lt;h3&gt;Gameplay and Interface Changes&lt;/h3&gt;
&lt;p&gt;I removed most of the cats’ attributes from the user interface to focus on the
feeding mechanic.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="new-asset-pipeline"&gt;
&lt;h3&gt;New Asset Pipeline&lt;/h3&gt;
&lt;p&gt;I implemented a basic asset pipeline. I was previously using a single image
(texture atlas) as the image source for both Tiled and the game config. This
became a bit inconvenient as I rearranged tiles on the image; I had to update
game config as well as manually redraw the map in Tiled each time. I found a
thread where the Tiled author recommends using single images (one per tile) as
the source for the tileset.  There is now a simple asset pipeline for tile images
that works like this:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;Create a new image in Aseprite and save in .ase format.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;From each .ase image, create a .png image for use in Tiled.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;From all .ase images, generate a .png texture atlas for use in ng.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All steps after the first are automated using GNU make.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="the-tech"&gt;
&lt;h2&gt;The Tech&lt;/h2&gt;
&lt;p&gt;Here’s the ng diff:&lt;/p&gt;
&lt;div class="highlight-text notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span/&gt; doc/plan/plan.rst | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/doc/plan/plan.rst b/doc/plan/plan.rst
index cc3b252..4e23e3e 100644
--- a/doc/plan/plan.rst
+++ b/doc/plan/plan.rst
@@ -1,6 +1,8 @@
 To do
 =====

+- Fix pick functionality when device-independent resolution doesn't
+  match actual window size.
 - Reusable logging configuration for each module.
 - Support multiplicative color modification of entities.
 - Add collision info to event system.
@@ -14,6 +16,28 @@ To do
 Finished
 ========

+2018-03-21
+----------
+
+- Support bold font in textarea gadget.
+- Support getting currently pressed keys.
+- Support setting device-independent resolution for renderer.
+
+2018-03-20
+----------
+
+- Add debug bounding box highlight.
+
+2018-03-19
+----------
+
+- Use Aseprite JSON file to unpack texture atlas coordinates.
+
+2018-03-15
+----------
+
+- On-demand reloading of changed texture resources from filesystem.
+
 2018-03-14
 ----------
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;I added some features I know I’ll need for an upcoming project. Also, some of
what I’ve been doing has been catching up with me, so I added several features
to make things easier to use.&lt;/p&gt;
&lt;section id="logical-resolution"&gt;
&lt;span id="ogam-march-cats-2-logical-resolution"/&gt;&lt;h3&gt;Logical Resolution&lt;/h3&gt;
&lt;p&gt;Also known as device-independent resolution, this will make it more convenient
to work with smaller pixel dimensions in the future.&lt;/p&gt;
&lt;p&gt;As I mentioned &lt;a class="reference internal" href="#new-graphics"&gt;&lt;span class="std std-ref"&gt;earlier&lt;/span&gt;&lt;/a&gt;, I’m currently using a 16x16 base
tile size for Cats. The resulting graphics are tiny in a 1280x1024 window. To
make things visible, a 4x scaling factor is applied in both directions, so each
texture pixel becomes 16 real pixels at runtime. This works, but is
inconvenient since I have to apply the scaling factor to every entity
individually in game config.&lt;/p&gt;
&lt;p&gt;Normally, it’s desirable to apply the same scale to all graphics, so the
ability to set a global logical resolution will be convenient. It is done like
this: &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;ng.resolution(640,&lt;/span&gt; &lt;span class="pre"&gt;480)&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Because of the way SDL’s GetMouseState routine works, this feature currently
breaks mouse coordinates and picking. I won’t convert Cats to use it until
that is fixed.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="texture-reloading"&gt;
&lt;h3&gt;Texture Reloading&lt;/h3&gt;
&lt;p&gt;Texture reloading supports reloading changed texture files into
the running game without a restart. The in-game entities using the textures are updated
instantly with the changes. This is done by calling
&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;ng.resources_reload()&lt;/span&gt;&lt;/code&gt;, which I bind to the &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;R&lt;/span&gt;&lt;/code&gt; key in the game.&lt;/p&gt;
&lt;figure class="align-default" id="id2"&gt;
&lt;img alt="../_images/2018-03-23_animation_test.gif" src="../_images/2018-03-23_animation_test.gif"/&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;You know, animation testing&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;This feature is useful when adjusting the tile graphics or doing animation
testing. For example, an artist might change a few pixels in an animation
frame, save a new version of the image, and reload the resources to see the
changes to the animation immediately without restarting the program.&lt;/p&gt;
&lt;p&gt;Later, support can be extended to handle changes to all resource types,
including configuration!&lt;/p&gt;
&lt;/section&gt;
&lt;section id="bounding-box-highlight"&gt;
&lt;h3&gt;Bounding Box Highlight&lt;/h3&gt;
&lt;p&gt;Bounding box highlight draws each entity’s bounding box, using alpha
transparency to show overlapping boxes. This is toggled with the boolean
&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;ng.debug['bounding_box']&lt;/span&gt;&lt;/code&gt;, which I bind to the &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;B&lt;/span&gt;&lt;/code&gt; key in the game.  This
is useful for troubleshooting collision detection issues.&lt;/p&gt;
&lt;figure class="align-default" id="id3"&gt;
&lt;img alt="../_images/2018-03-22_debug_bounding_box.gif" src="../_images/2018-03-22_debug_bounding_box.gif"/&gt;
&lt;figcaption&gt;
&lt;p&gt;&lt;span class="caption-text"&gt;Debug bounding boxes&lt;/span&gt;&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/section&gt;
&lt;section id="texture-atlas-support"&gt;
&lt;h3&gt;Texture Atlas Support&lt;/h3&gt;
&lt;p&gt;I’ve been manually updating the atlas coordinates of individual textures in
game config, which becomes tedious-to-unfeasible as the number of textures
grows and they are rearranged on the atlas image by the packing algorithm.
Aseprite writes a JSON file with texture coordinates when it exports an atlas.
ng can now use this file to find map tile coordinates in the atlas image.  It’s
not working yet for entity textures in general; I’ll work on that at the same
time as I fix up some rough edges around the animation system in preparation
for the April OGAM.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="bugs"&gt;
&lt;h3&gt;Bugs&lt;/h3&gt;
&lt;p&gt;For a few days, I tolerated a bug that caused Cats to lock up after a few
minutes.  I first noticed the problem around the same time I had some other
strange issues with one of my video card’s ports. Fearing the first, like an OS
driver issue or even a hardware issue, I avoided investigating for awhile.
Digging in on Wednesday, I reproduced the issue on my laptop, suggesting a
local software problem instead.&lt;/p&gt;
&lt;p&gt;I tested a new skeleton pysdl rendering program, which didn’t show the problem.
I then added back ng’s calls until I found the issue. nui, ng’s user interface
API, created new textures every frame for the text that displays the program
time and performance information. It didn’t remove the previous frame’s
textures, so it eventually consumed all available memory. This made the program
unresponsive and caused the system to perform poorly until the program finished
and the OS reclaimed the resources. Correctly freeing the old textures each
frame resolved the issue.&lt;/p&gt;
&lt;p&gt;I told M. this story and he asked me what I learned. At first I said “not
much”; the cause of the bug was directly along the lines I suspected and it
“only” took an hour or so to fix (hubris).&lt;/p&gt;
&lt;p&gt;As we talked about that, I thought about it more and decided I had learned
something that now seems obvious. When writing an interactive software with a
render loop, it’s important to start long-running testing as early as possible
and do it frequently. I’ve been writing example programs to exercise ng’s
features, but have been running them quickly to verify functionality and
stopping them. I can improve these by making them repeat and leaving them
running, verifying ng’s stability over time and noticing regressions sooner.&lt;/p&gt;
&lt;p&gt;Secondly, the conditions under which a recurring bug is discovered shouldn’t
bias the programmer’s attitude toward it.  I shouldn’t have feared a driver or
OS issue before investigating. I have been programming for several years and
still make this kind of mistake more than I’d like. The human brain is great at
establishing patterns, which can lead to counterproductive assumptions
sometimes.&lt;/p&gt;
&lt;p&gt;Finally, I have to admit the cost to fix this was more than the hour I measured
after I finally decided to focus on it. The issue was a little distracting over
the last several days and stopped me from doing long-running testing. What’s
the real cost of that?&lt;/p&gt;
&lt;p&gt;We must not fear or tolerate user-facing bugs.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="summary"&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;Thanks for reading. Next week, we’ll do a retrospective on Cats and do some
planning for April.&lt;/p&gt;
&lt;/section&gt;
</description><pubDate>Fri, 23 Mar 2018 00:00:00 </pubDate></item><item><title>Cats update 1 (One Game a Month, March)</title><link>http://www.mahnke.tech/blog/2018-03-11-ogam-march-cats.html</link><description>

&lt;p&gt;&lt;em&gt;Published on 2018-03-14.&lt;/em&gt;&lt;/p&gt;
&lt;section id="the-project"&gt;
&lt;h2&gt;The Project&lt;/h2&gt;
&lt;p&gt;It’s about the halfway mark for OGAM March 2018. Now is a good opportunity to
check progress and recalibrate efforts around the second half of the month.&lt;/p&gt;
&lt;p&gt;The March One Game a Month entry takes an idea that came from a brainstorming
session with my friend and roommate M. a few months ago. The idea: feed cats to
the benefit or detriment of their health.&lt;/p&gt;
&lt;p&gt;There are many virtual pet games, and my experience with them minimal. I had
the original Dogz, but was too old for Tamagotchi by a few years. I have the
impression the genre as a whole focuses on fantastical elements to keep the
user interested, and there may be many parts of ordinary pet interactions yet
to be explored in a game.&lt;/p&gt;
&lt;p&gt;Here’s the list I jotted after the OGAM March theme of PERMANENCE was
announced:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;Satiation. Cats may be more satisfied by some foods than others.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Nutrition. Different foods augment cats’ attributes in different ways.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Food preference. Cats prefer some foods over others.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Breeding. Cats have the opportunity to breed with other cats and produce
offspring with attributes from both parents.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Religion. Cats may have religions that affect their demeanor and their
relationships with other cats.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Weight management. Overfeeding cats will increase weight, but diminish the
other benefits of food. Weight too low/too high causes death or other health
problems.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Permadeath. When a cat dies, a headstone is created in the yard for it.
Passed cats may deliver the occasional boon or burden to the player from
beyond the grave.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Equipment upgrades to incorporate idle game elements. e.g. auto-feeder.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here’s the plan of record, which I created around the same time as the previous
list and have been working from daily. Going forward, I’ll probably just use
diffs in these blog posts.&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span/&gt;Feature planned for future/maybe
================================

- Human interaction with cats.
- A friendly tutorial.
- Breed with neighborhood cats.

Features planned for OGAM deadline
==================================

- Cat feeding and care.
- Day and night cycle.
- Permanence: every character is permanent.
- Cat-racter generation.
- Religion/horoscopes.
- Two music tracks.

To do
=====

Future/maybe
------------

- Communicate changes to user with a popup or scrolling marquee.
- Cat is more/less likely to eat food based on preference.
- Food degrades/spoils over time?
- Some food is turned into waste and cats poop.

2018-03-28 milestone
--------------------

- Support metric units.

2018-03-21 milestone
--------------------

- Add save/load game state functionality.
- Add breeds.
- Bug: death animations are visible from other scenes.
- View legacy of passed cats.

2018-03-14 milestone
--------------------

- Add pause functionality.

Finished
========

2018-03-10
----------

- Add log view to show a full screen of log messages.
- Show last few messages of history log on main screen.
- Add a history log, so the user can review the events of the past.
- Add keyboard help screen.
- Hunting consumes energy and cat can only hunt with enough energy left.
- Sleep restores energy.

2018-03-09
----------

- Cats gain toxicity when eating foods that carry it.
- Cat can hunt to get its own food.
- Add inventory management of food; food is now a finite resource.
- Create new cat when existing one dies.
- Add messages on cause of death.
- Add cat age (months and years).
- Cat leaves headstone in yard after death.

2018-03-08
----------

- Cat gains weight when eating and loses weight when not eating.
- Cat dies outside of a healthy weight range.
- Randomly assign name, sex, and religion to new cats.

2018-03-06
----------

- Cat faces the correct left/right direction based on direction of movement.
- Support tile rotation/mirror for map.
- Cat stops moving with wall collision.
- Cat wanders around the room.
- Day and night transition.
- Draw yard floor tile.
- Draw grave head stone.
- Switch between house and yard views.
- Show cat statistics in a UI gadget.

2018-03-05
----------

- Add floor tiles to scene.

2018-03-04
----------

- Add food dish to scene.
- Present feed window when 'f' key is pressed.
- When user selects a food from the window, feed the cat and augment
  its statistics.
- Add a coffee table to the scene.
- Add a refrigerator to the scene.
- Add windows to the scene.
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Here’s what the game looks like today. These are cats in a house.&lt;/p&gt;
&lt;img alt="../_images/cat_mahlzeit_2018-03-12_0.png" src="../_images/cat_mahlzeit_2018-03-12_0.png"/&gt;
&lt;p&gt;I turned up the challenge level and created a grim scene pretty quickly. These
are the headstones of the deceased in the back yard.&lt;/p&gt;
&lt;img alt="../_images/2018-03-13_graveyard.png" src="../_images/2018-03-13_graveyard.png"/&gt;
&lt;p&gt;What’s emerged feels like a cat hunting simulation with roguelike elements.  I
wanted this kind of twitch cat digestion management idea to work and be
entertaining, but I started to stress about balancing it. I realized that,
while hardcore cat survival sounds like it could be pretty fun, it’s probably
not the kind of game I’m inspired to make and play right now. If I can focus on
just a few interesting aspects of feline existence this month, hunting prey to
keep that digestive machine moving is probably not near the top.&lt;/p&gt;
&lt;p&gt;For the next few days, I’ll play around with the more cozy facets of day-to-day
life for a cat: sleeping, eating too much and getting fat, getting into fights
with other cats over food and toys, and manipulating humans.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="the-tech"&gt;
&lt;h2&gt;The Tech&lt;/h2&gt;
&lt;p&gt;I introduced ng, the engine I’m writing for all OGAM 2018 efforts, in the
&lt;a class="reference external" href="2018-03-11-introducing-ng-engine.html"&gt;previous post&lt;/a&gt;. Here’s a look at how
ng changed to support the work over the last few days. Again, this is the
entire plan file thus far and I’ll probably show diffs in future posts.&lt;/p&gt;
&lt;div class="highlight-text notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span/&gt;To do
=====

- Reusable logging configuration for each module.
- Support multiplicative color modification of entities.
- Add collision info to event system.
- Implement Python configuration DSL.
- Better classes around event system.
- Add/remove debug and performance statistics with 'z' key.
- Support center point (pivot point) for rotation.
- Simple IPython integration.
- Annotation-based profiler.
- Add copyright/licensing info to files on build.

Finished
========

2018-03-12
----------

- x/y entity scaling.
- Frame animation support.

2018-03-11
----------

- Support getting mouse cursor position within window.

2018-03-10
----------

- Bug: Fix child gadget id assignment problem.
- Get gadgets by name.
- Add and delete timers by name (named timers).
- Focus new nui text area controls and dismiss any keypress.

2018-03-09
----------

- Add support for playing sound effects in WAV format.
- Add support for z coordinate so user can control rendering order (2d depth).
- Add "visible" attribute of entity to determine whether or not it is rendered.

2018-03-07
----------

- Cleanly shutdown SDL on exit.
- Abstract SDL_RenderClear, etc. operations.

2018-03-06
----------

- Implement background color for nui gadgets.
- Support entity horizontal/vertical flip.
- Support entity rotation.
- Stop objects that collide with solid objects.
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Since ng is a new engine, most of the current work is on essential features
that you would find in any 2D game.&lt;/p&gt;
&lt;p&gt;Here are a few highlights of the new features and how to use them with the ng
API. You’ll see references to &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;self._ng&lt;/span&gt;&lt;/code&gt;, which is an instance created
outside of the code example. I may add more comprehensive examples in future
posts.&lt;/p&gt;
&lt;section id="collision-detection"&gt;
&lt;h3&gt;Collision detection&lt;/h3&gt;
&lt;p&gt;Having game state react in some way to two entities touching one another is
ubiquitous, and I had to add this so cats can wander around without walking
through walls. Here’s how this functionality looks in isolation. When any of
the moving blocks touch the center stationery block, they stop.&lt;/p&gt;
&lt;img alt="../_images/2018-03-13_collision.gif" src="../_images/2018-03-13_collision.gif"/&gt;
&lt;p&gt;Here’s the code fragment needed to set up this little test.&lt;/p&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span/&gt;&lt;span class="linenos"&gt; 1&lt;/span&gt;&lt;span class="n"&gt;block1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_ng&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;entity_create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'block1'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;250&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;250&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="linenos"&gt; 2&lt;/span&gt;    &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;texture&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'block'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'rect'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;)},&lt;/span&gt;
&lt;span class="linenos"&gt; 3&lt;/span&gt;    &lt;span class="n"&gt;collides&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="linenos"&gt; 4&lt;/span&gt;&lt;span class="n"&gt;block2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_ng&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;entity_create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'block2'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;250&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="linenos"&gt; 5&lt;/span&gt;    &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;texture&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'block'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'rect'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;)},&lt;/span&gt;
&lt;span class="linenos"&gt; 6&lt;/span&gt;    &lt;span class="n"&gt;collides&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;color_mod&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="linenos"&gt; 7&lt;/span&gt;&lt;span class="n"&gt;block3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_ng&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;entity_create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'block3'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;250&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="linenos"&gt; 8&lt;/span&gt;    &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;texture&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'block'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'rect'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;)},&lt;/span&gt;
&lt;span class="linenos"&gt; 9&lt;/span&gt;    &lt;span class="n"&gt;collides&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;color_mod&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="linenos"&gt;10&lt;/span&gt;&lt;span class="n"&gt;block4&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_ng&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;entity_create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'block4'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;250&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="linenos"&gt;11&lt;/span&gt;    &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;texture&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'block'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'rect'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;)},&lt;/span&gt;
&lt;span class="linenos"&gt;12&lt;/span&gt;    &lt;span class="n"&gt;collides&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;color_mod&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="linenos"&gt;13&lt;/span&gt;&lt;span class="n"&gt;block5&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_ng&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;entity_create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'block5'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;250&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="linenos"&gt;14&lt;/span&gt;    &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;texture&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'block'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'rect'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;)},&lt;/span&gt;
&lt;span class="linenos"&gt;15&lt;/span&gt;    &lt;span class="n"&gt;collides&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;color_mod&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="linenos"&gt;16&lt;/span&gt;
&lt;span class="linenos"&gt;17&lt;/span&gt;&lt;span class="n"&gt;block2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;velocity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="linenos"&gt;18&lt;/span&gt;&lt;span class="n"&gt;block3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;velocity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="linenos"&gt;19&lt;/span&gt;&lt;span class="n"&gt;block4&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;velocity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="linenos"&gt;20&lt;/span&gt;&lt;span class="n"&gt;block5&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;velocity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Setting the &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;collides&lt;/span&gt;&lt;/code&gt; attribute on an entity adds it to collision
processing.  The collision processing in ng is currently very primitive. Each
frame, each entity’s position is updated according to its velocity. After this
is done, entities with &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;collides&lt;/span&gt;&lt;/code&gt; are all bounding box tested against one
another, and a list of collided entities is created. After all tests are
complete, the collided entities are moved back to their position at the
beginning of the frame.&lt;/p&gt;
&lt;p&gt;This is enough physics to finish Cats. I’m not sure ng should resolve entity
positions after collision, though. After Cats is finished, I may change it to
fire an event with collision details and let the programmer decide what to do
with them.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="frame-animation"&gt;
&lt;h3&gt;Frame animation&lt;/h3&gt;
&lt;p&gt;Frame animation is an essential 2D art technique, and I had to add it to bring
some cats to life. Here’s a simple animation test.&lt;/p&gt;
&lt;img alt="../_images/2018-03-12_animation.gif" src="../_images/2018-03-12_animation.gif"/&gt;
&lt;p&gt;Here’s what’s necessary to do that.&lt;/p&gt;
&lt;div class="highlight-python notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span/&gt;&lt;span class="linenos"&gt; 1&lt;/span&gt;&lt;span class="c1"&gt;# Definitions&lt;/span&gt;
&lt;span class="linenos"&gt; 2&lt;/span&gt;
&lt;span class="linenos"&gt; 3&lt;/span&gt;&lt;span class="n"&gt;ANIM_FRAMES_CAT_WALK&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'walk'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'frames'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="linenos"&gt; 4&lt;/span&gt;&lt;span class="n"&gt;ANIM_FRAMES_CAT_STOP&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'stop'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'frames'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'first'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
&lt;span class="linenos"&gt; 5&lt;/span&gt;
&lt;span class="linenos"&gt; 6&lt;/span&gt;&lt;span class="n"&gt;ANIM_INFO_CAT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'a_i_cat'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'texture'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'cat_walk'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="linenos"&gt; 7&lt;/span&gt;    &lt;span class="s1"&gt;'texture_origin'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="linenos"&gt; 8&lt;/span&gt;    &lt;span class="s1"&gt;'frame_size'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;'animation_frames'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'walk'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'stop'&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;
&lt;span class="linenos"&gt; 9&lt;/span&gt;
&lt;span class="linenos"&gt;10&lt;/span&gt;&lt;span class="n"&gt;ANIM_CAT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'a_cat'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'info'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'a_i_cat'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'frame_duration'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.15&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="linenos"&gt;11&lt;/span&gt;
&lt;span class="linenos"&gt;12&lt;/span&gt;&lt;span class="n"&gt;CAT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'cat'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'position'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;'size'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="linenos"&gt;13&lt;/span&gt;    &lt;span class="s1"&gt;'texture'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'sheet'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'rect'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;192&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;)},&lt;/span&gt;
&lt;span class="linenos"&gt;14&lt;/span&gt;    &lt;span class="s1"&gt;'velocity'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;'collides'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'animation'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'a_cat'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="linenos"&gt;15&lt;/span&gt;
&lt;span class="linenos"&gt;16&lt;/span&gt;&lt;span class="c1"&gt;# Code to create objects&lt;/span&gt;
&lt;span class="linenos"&gt;17&lt;/span&gt;
&lt;span class="linenos"&gt;18&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_ng&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;anim_frames_create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ANIM_FRAMES_CAT_WALK&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="linenos"&gt;19&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_ng&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;anim_frames_create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ANIM_FRAMES_CAT_STOP&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="linenos"&gt;20&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_ng&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;anim_info_create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ANIM_INFO_CAT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="linenos"&gt;21&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_ng&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;anim_create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ANIM_CAT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The definitions section specifies all the data needed at runtime.  The code
section shows all the calls needed to create the animated entities.  The first
three create calls are one-time setup steps, and the fourth could be called
multiple times to create any number of animated entities.&lt;/p&gt;
&lt;p&gt;This syntax is slightly different than in the previous example. Here, we create
dicts to hold the necessary data, and then send them as keyword arguments to
the creation methods. This pattern separates executable code from data; in
Cats, I have configuration data in a separate configuration file for easy
modification.&lt;/p&gt;
&lt;p&gt;I’m pretty happy with this syntax, but I plan to add a cascading entity
creation feature to make it briefer. The &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;entity_create&lt;/span&gt;&lt;/code&gt; call will take care
of all the supporting data structures, and that will make the first three
creation calls unnecessary.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="summary"&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;Thanks for reading. I’ll post another update next week.&lt;/p&gt;
&lt;/section&gt;
</description><pubDate>Wed, 14 Mar 2018 00:00:00 </pubDate></item><item><title>Introducing ng engine</title><link>http://www.mahnke.tech/blog/2018-03-11-introducing-ng-engine.html</link><description>

&lt;p&gt;&lt;em&gt;Published on 2018-03-11.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;ng is the engine I’m building to support my &lt;a class="reference external" href="http://www.onegameamonth.com/"&gt;OGAM&lt;/a&gt; development efforts in 2018.  The name “ng”
is a working title and has little personal significance. There’s a major
advantage to short names when using them in code, especially when using C.&lt;/p&gt;
&lt;p&gt;I wrote about my decision to write my own engine &lt;a class="reference external" href="2018-03-08-one-game-a-month.html"&gt;here&lt;/a&gt;. There are many build vs. reuse arguments;
I didn’t make that kind of evaluation this time.&lt;/p&gt;
&lt;p&gt;My personal goals for the project are to achieve proficiency in the following
areas:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;2D and 3D graphics engine architecture.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Mathematics for 2D and 3D graphics.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;User interface architecture.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;SDL and OpenGL APIs.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;My technical goals for the project are as follows:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;Absolute control. The program designer will be in complete control of the
event loop. The programmer will use ng, rather than ng using the programmer’s
code.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Excellent tooling, with a strong focus on debug facilities and tools to solve
problems and protect against regressions as they arise.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Top-notch Python scripting support. Since ng is currently being written in
pure Python, this is a given.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Notably absent from the list:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;General purpose feature completeness. This is a toy and educational project
with a scope as such. To say a “feature” is done in this project does not
require “feature completeness”.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Absolute performance. There are no absolute performance requirements.
Performance issues will be addressed if and when they surface in use.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So far, specific feature requirements have been unplanned and driven by need of
OGAM requirements. Since I have OGAM features planned through the end of April,
I could conceivably create a two-month roadmap, and might do that in a future
post.&lt;/p&gt;
&lt;p&gt;See you in a few days, when we’ll examine weekly progress on both ng and the
OGAM March 2018 entry.&lt;/p&gt;
</description><pubDate>Sun, 11 Mar 2018 00:00:00 </pubDate></item><item><title>One Game a Month</title><link>http://www.mahnke.tech/blog/2018-03-08-one-game-a-month.html</link><description>

&lt;p&gt;&lt;em&gt;Published on 2018-03-08.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I recently committed to submitting to &lt;a class="reference external" href="http://www.onegameamonth.com"&gt;One Game a Month&lt;/a&gt; for the remainder of
2018, beginning in March. I’ve been interested in partipating in jams for a
long time. More recently, the idea of using constraints to intentionally
restrict the scope of my projects has become appealing. This fits naturally
with the time limits for jams &lt;a class="footnote-reference brackets" href="#id4" id="id1" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;1&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I’m not completely new to the idea of developing graphical games and
simulations. I’ve worked on a few projects in this area. From memory:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;When I first decided to develop software professionally, I started learning
C++ by attempting a &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Gauntlet_(series)"&gt;Gauntlet&lt;/a&gt;-style dungeon crawler (SFML, C++, circa 2010).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I learned the value of using engines as aids to speed development (I would
learn their value as reference material &lt;strong&gt;much&lt;/strong&gt; later). I programmed a game
called Equilibria for the now-defunct indie team AntEye Games. The project
was never completed (&lt;a class="reference external" href="http://www.orx-project.org"&gt;orx&lt;/a&gt; &lt;a class="footnote-reference brackets" href="#id5" id="id2" role="doc-noteref"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;2&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/a&gt;, C++, 2011-2012).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I started a text-only game in C where you are a convenience store manager
with all the responsibilities that accompany it (ncurses, C++, 2016).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I got interested in rendering and started a software 2d/3d renderer
supporting wireframe geometry rendering and orthographic projection (SDL, C).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You might notice a trend toward both more abstract ideas and lower-level
technical interests.&lt;/p&gt;
&lt;p&gt;I’ve started probably 10-20 other less personally significant game-like
projects.&lt;/p&gt;
&lt;p&gt;It feels like it has taken many years and twice as many unfinished projects for
experience and skill to come together well enough to potentially finish some
things, so here we are with a proclamation of commitment and a new blog to
chronicle the journey.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Here are my personal 2018 jamming rules.&lt;/strong&gt;&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;No third-party engines. It didn’t occur to me to evaluate game engine choices
this time. Instead, I opted to create my own engine to support these
projects. This decision puts interesting constraints on freedom of choice;
when I want a feature that doesn’t exist yet, I must either develop it and
spend less time on the jam idea, or sacrifice it and make the jam idea work
without that feature. Constraints aside, each feature added is a learning
experience.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Only &lt;a class="reference external" href="https://www.fsf.org/about/what-is-free-software"&gt;Free software&lt;/a&gt; is allowed in the development environment. Note that
“free” as used here does not mean gratis and has nothing to do with monetary
cost, but rather refers to the freedoms granted to the user by the software’s
license(s). This decision is for political/idealogical reasons.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The current toolset for engine development is Arch Linux, neovim, Python 3,
SDL2, and OpenGL. Game-specific tools are gimp for image editing and tiled for
map editing. This list will change as development continues. Third-party tools
will be added, and will also be removed as internal tools are developed.&lt;/p&gt;
&lt;p&gt;These posts will document both the engine and the game creation process. I hope
what I learn might both be helpful to others and be another interesting point
of reflection for 2019 Me.&lt;/p&gt;
&lt;aside class="footnote-list brackets"&gt;
&lt;aside class="footnote brackets" id="id4" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;&lt;a role="doc-backlink" href="#id1"&gt;1&lt;/a&gt;&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;Why do game developers get all the fun? Are there jams for other
software industries?&lt;/p&gt;
&lt;/aside&gt;
&lt;aside class="footnote brackets" id="id5" role="doc-footnote"&gt;
&lt;span class="label"&gt;&lt;span class="fn-bracket"&gt;[&lt;/span&gt;&lt;a role="doc-backlink" href="#id2"&gt;2&lt;/a&gt;&lt;span class="fn-bracket"&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;Take a moment and look at &lt;a class="reference external" href="http://www.orx-project.org"&gt;orx&lt;/a&gt;. The principal contributor is a great
programmer and a friend and teacher of mine.&lt;/p&gt;
&lt;/aside&gt;
&lt;/aside&gt;
</description><pubDate>Thu, 08 Mar 2018 00:00:00 </pubDate></item></channel></rss>