Monday, November 2, 2015

Handlebars Essentials

Handlebars is a good little helper library for client-side Javascript development. It allows creating templates MVC-style in an HTML page and binding to data sources.
Here are my Handlebars code bits as a reference.

1. A page with a target element.
<!DOCTYPE html>
<html>
<head>
    <script src="lib/jquery/jquery-2.1.4.min.js"></script>
    <script src="lib/handlebars/handlebars-v4.0.4.js"></script>
    <script src="lib/material-design-lite/material.min.js"></script>
    <script src=“js/MV.js"></script>
    <script src="js/app.js"></script>
</head>

<body>
    <div id="main" class=“mail-class">
    </div>
</body>
</html>


2. A page template. This is the main container of all visible elements.
<script type="text/x-handlebars-template" id="index-template">
  <div class="header">
    <div class="title">
        <h1>{{siteTitle}}</h1>
    </div>
    <div>
      <nav class="navigation">
        <a href="?option=page1">{{page1Name}}</a>
        <a href="?option=page2">{{page2Name}}</a>
        <a href="?option=page3">{{page3Name}}</a>
      </nav>
    </div>
  </div>
  <div class="content">
    <div id="theItems">
    </div>
    <footer class="footer">
    </footer>
  </div>
</script>

3. Partial templates (partials). These simplify code structure by allowing to refactor templates as components into separate source files.
<script type="text/x-handlebars-template" id="item-template">
  <div class="item-card” data-item-id="{{id}}">
    <div class="card-title" style="background: url('images/{{image}}') center 15% no-repeat #46B6AC;">
        <h2>{{name}}</h2>
    </div>
    <div class="card-border">
      <button class="button-one">
        {{language.one}}
      </button>
      <button class="button-two">
        {{language.two}}
      </button>
    </div>
    {{#if moreInfo}}
      {{#if isCorrect}}
        <span class="result-good">{{language.correct}}</span>
      {{else}}
        <span class="result-bad">{{language.incorrect}}</span>
      {{/if}}
    {{/if}}
  </div>
</script>

4. A template-iterator. This implements iteration through items and also references a partial template for rendering an individual item.
<script type="text/x-handlebars-template" id="items-template">
  {{#each items}}
    {{> item language=@root.language}}
  {{else}}
    {{language.noItemsFoundMessage}}
  {{/each}}
</script>

5. A script (app.js) to register partials and to render a page. Also binds page elements to event handlers.
(function() {

  $(function () {
    registerPartials();
    renderPage();
    renderItems();
  });

  function registerPartials() {
    Handlebars.registerPartial("item", $("#item-template").html());
  }

  function renderPage() {
    var template = $("#index-template").html();
    var compiled = Handlebars.compile(template);
    var rendered = compiled(window.language);
    $("#main").html(rendered);
    $("#languageSwitch").click(function() {
      MV.switchLanguage();
    });
  }

  function renderItems() {
    var template = $("#items-template").html();
    var compiled = Handlebars.compile(template);
    var rendered = compiled({ items: MV.items, language: window.language });
    $("#theItems").html(rendered);
    attachItemsButtons();
  }

  function attachItemsButtons() {
    $(".button-one").click(function() {
      var id = $(this).closest(".item-card").data("item-id");
      MV.itemActionOne(id);
      renderItems();
    });

    $(".button-two").click(function() {
      var id = $(this).closest(".item-card").data("item-id");
      MV.itemActionTwo(id);
      renderItems();
    });
  }

})();

6. Helpers. These are global functions that can be invoked out of any context. “this” will refer to a current context.
For example, in helpers.js:
Handlebars.registerHelper("getLanguageFilter", function(langId) {
  var queryParam = "";
  if (langId) {
    queryParam = "&language=" + Handlebars.escapeExpression(langId);
  }
  return new Handlebars.SafeString(queryParam);
});

Handlebars.registerHelper("generatePages", function(items) {
  var pages = [];
  var pageCount = Math.ceil(items.length / 10);
  for (var i = 1; i <= pageCount; i++) {
    var link = “?page=" + i;
    pages.push({
      number: i,
      link: link
    });
  }
  return pages;
});

Then, in a page or in a template:
<!-- Navigation -->
<script type="text/x-handlebars-template" id=“navigation-template">
  <div>
      <nav class="mdl-navigation">
          <a href="?filter=ones{{getLanguageFilter langId}}">{{itemsFilterOne}}</a>
          <a href="?filter=twos{{getLanguageFilter langId}}">{{itemsFilterTwo}}</a>
      </nav>
  </div>
</script>
...
<script type="text/x-handlebars-template" id="page-template">
  <ul>
    {{#each (generatePages items)}}
      <li><a href="{{link}}">{{number}}</a></li>
    {{/each}}
  </ul>
</script>

Thursday, August 20, 2015

C++11 smart_ptr and weak_ptr best practices

C++ waited almost a decade to finally adopt one of the two most ubiquitous memory management models

Tuesday, April 28, 2015

Rendering multiple objects with instanced arrays

1. One of the methods to render instanced arrays calls for specific setup of WVP matrices:

int pos = glGetAttribLocation(shader_instancedarrays.program, "transformmatrix");
int pos1 = pos + 0;
int pos2 = pos + 1;
int pos3 = pos + 2;
int pos4 = pos + 3;
glEnableVertexAttribArray(pos1);
glEnableVertexAttribArray(pos2);
glEnableVertexAttribArray(pos3);
glEnableVertexAttribArray(pos4);
glBindBuffer(GL_ARRAY_BUFFER, VBO_containing_matrices);
glVertexAttribPointer(pos1, 4, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 4 * 4, (void*)(0));
glVertexAttribPointer(pos2, 4, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 4 * 4, (void*)(sizeof(float) * 4));
glVertexAttribPointer(pos3, 4, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 4 * 4, (void*)(sizeof(float) * 8));
glVertexAttribPointer(pos4, 4, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 4 * 4, (void*)(sizeof(float) * 12));
glVertexAttribDivisor(pos1, 1);
glVertexAttribDivisor(pos2, 1);
glVertexAttribDivisor(pos3, 1);
glVertexAttribDivisor(pos4, 1);


and then draw the elements:

glDrawElementsInstanced(primitivetype, indices, GL_UNSIGNED_INT, 0, instancecount);

shader:

attribute mat4 transformmatrix;

void main()
{
    mat4 mvp = gl_ModelViewProjectionMatrix * transformmatrix;

    gl_Position = mvp * gl_Vertex;
    gl_TexCoord[0] = gl_MultiTexCoord0;
}


2. Instance-specific attributes (WVP matrices) go into a separate vertex buffer. Vertex attributes will be read and applied for each vertex, but WVP matrix in this example will stay unchanged until all vertices have been accessed. Then the program will read a new WVP matrix, and repeat rendering all vertices.

3. Use a built-in shader variable gl_InstanceID. Use this index to access instance-specific data in uniform variable arrays (http://ogldev.atspace.co.uk/www/tutorial33/tutorial33.html).

bool Mesh::InitFromScene(const aiScene* pScene, const string& Filename)
{
...
// Generate and populate the buffers with vertex attributes and the indices

glBindBuffer(GL_ARRAY_BUFFER, m_Buffers[POS_VB]);
glBufferData(GL_ARRAY_BUFFER, sizeof(Positions[0]) * Positions.size(), &Positions[0],
GL_STATIC_DRAW);
glEnableVertexAttribArray(POSITION_LOCATION);
glVertexAttribPointer(POSITION_LOCATION, 3, GL_FLOAT, GL_FALSE, 0, 0); 

glBindBuffer(GL_ARRAY_BUFFER, m_Buffers[TEXCOORD_VB]);
glBufferData(GL_ARRAY_BUFFER, sizeof(TexCoords[0]) * TexCoords.size(), &TexCoords[0],
GL_STATIC_DRAW);
glEnableVertexAttribArray(TEX_COORD_LOCATION);
glVertexAttribPointer(TEX_COORD_LOCATION, 2, GL_FLOAT, GL_FALSE, 0, 0);

glBindBuffer(GL_ARRAY_BUFFER, m_Buffers[NORMAL_VB]);
glBufferData(GL_ARRAY_BUFFER, sizeof(Normals[0]) * Normals.size(), &Normals[0],
GL_STATIC_DRAW);
glEnableVertexAttribArray(NORMAL_LOCATION);
glVertexAttribPointer(NORMAL_LOCATION, 3, GL_FLOAT, GL_FALSE, 0, 0);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_Buffers[INDEX_BUFFER]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Indices[0]) * Indices.size(), &Indices[0],
GL_STATIC_DRAW);

glBindBuffer(GL_ARRAY_BUFFER, m_Buffers[WVP_MAT_VB]);

for (unsigned int i = 0; i < 4 ; i++) {
    glEnableVertexAttribArray(WVP_LOCATION + i);
    glVertexAttribPointer(WVP_LOCATION + i, 4, GL_FLOAT, GL_FALSE, sizeof(Matrix4f),
    (const GLvoid*)(sizeof(GLfloat) * i * 4));
    glVertexAttribDivisor(WVP_LOCATION + i, 1);
}

glBindBuffer(GL_ARRAY_BUFFER, m_Buffers[WORLD_MAT_VB]);

for (unsigned int i = 0; i < 4 ; i++) {
    glEnableVertexAttribArray(WORLD_LOCATION + i);
    glVertexAttribPointer(WORLD_LOCATION + i, 4, GL_FLOAT, GL_FALSE, sizeof(Matrix4f),
    (const GLvoid*)(sizeof(GLfloat) * i * 4));
    glVertexAttribDivisor(WORLD_LOCATION + i, 1);
}

return GLCheckError();
}

Note the use of offset in the glVertexAttribPointer in the last two buffer configurations. These are needed to make the mat4x4 (16 floats) to spread across 4 attribute locations. Normally one location is for a single attribute value and it needs to be 4 floats in size.
glVertexAttribDivisor instructs program to advance this specific location by instance, not by vertex. So it will read the next value after all vertices have been rendered, and will start a new instance from the beginning of the same vertex buffers.

In this case the actual data for WVP and world matrices is update each frame to make instances change their location.

More details:
The key element in making this work is to use glVertexAttribDivisor(). When using instanced rendering you basically tell openGL something like: draw N elements using e.g. GL_TRIANGLES and draw K vertices per instance. So if you have 1000 particles and you want to draw a square you can tell it to repeat a draw with 4 elements (4 elements will make a square when using GL_TRIANGLE_STRIP) and do to that 1000 times.

You use glVertexAtrribDivisor() to step through your VBO data, which will contain the vector of you particles and you tell openGL to only change the vertex attributes every X-instance. So glVertexAttribDivisor(0, 1) means that it will step through the data once per particle. The 0 here is referring to the vertex attribute location and the 1 is the number of times it should be changed per instance.


The function glVertexAttribDivisor() is what makes this an instance data rather than vertex data. It takes two parameters - the first one is the vertex array attribute and the second tells OpenGL the rate by which the attribute advances during instanced rendering. It basically means the number of times the entire set of vertices is rendered before the attribute is updated from the buffer. By default, the divisor is zero. This causes regular vertex attributes to be updated from vertex to vertex. If the divisor is 10 it means that the first 10 instances will use the first piece of data from the buffer, the next 10 instances will use the second, etc. We want to have a dedicated WVP matrix for each instance so we use a divisor of 1.

We repeat these steps for all four vertex array attributes of the matrix. We then do the same with the world matrix. Note that unlike the other vertex attributes such as the position and the normal we don't upload any data into the buffers. The reason is that the WVP and world matrices are dynamic and will be updated every frame. So we just set things up for later and leave the buffers uninitialized for now.

void Mesh::Render(unsigned int NumInstances, const Matrix4f* WVPMats, const Matrix4f* WorldMats)
    glBindBuffer(GL_ARRAY_BUFFER, m_Buffers[WVP_MAT_VB]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(Matrix4f) * NumInstances, WVPMats, GL_DYNAMIC_DRAW);

    glBindBuffer(GL_ARRAY_BUFFER, m_Buffers[WORLD_MAT_VB]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(Matrix4f) * NumInstances, WorldMats, GL_DYNAMIC_DRAW);

    glBindVertexArray(m_VAO);

    for (unsigned int i = 0 ; i < m_Entries.size() ; i++) {
        const unsigned int MaterialIndex = m_Entries[i].MaterialIndex;

        assert(MaterialIndex < m_Textures.size());

        if (m_Textures[MaterialIndex]) {
            m_Textures[MaterialIndex]->Bind(GL_TEXTURE0);
        }

        glDrawElementsInstancedBaseVertex(GL_TRIANGLES, 
                                         m_Entries[i].NumIndices, 
                                         GL_UNSIGNED_INT, 
                                         (void*)(sizeof(unsigned int) * m_Entries[i].BaseIndex), 
                                         NumInstances,
                                         m_Entries[i].BaseVertex);
    }

    // Make sure the VAO is not changed from the outside 
    glBindVertexArray(0);
}


Vertex shader.
Instead of getting the WVP and world matrics as uniform variables they are now coming in as regular vertex attributes. The VS doesn't care that their values will only be updated once per instance and not per vertex. As discussed above, the WVP matrix takes up locations 3-6 and the world matrix takes up locations 7-10.
The last line of the VS is where we see the second way of doing instanced rendering (the first being passing instance data as vertex attributes). 'gl_InstanceID' is a built-in variable which is available only in the VS. Since we plan to use it in the FS we have to access it here and pass it along in a regular output variable. The type of gl_InstanceID is an integer so we use an output variable of the same type. Since integers cannot be interpolated by the rasterizer we have to mark the output variable as 'flat' (forgetting to do that will trigger a compiler error).

#version 330

layout (location = 0) in vec3 Position; 
layout (location = 1) in vec2 TexCoord; 
layout (location = 2) in vec3 Normal; 
layout (location = 3) in mat4 WVP; 
layout (location = 7) in mat4 World; 

out vec2 TexCoord0; 
out vec3 Normal0; 
out vec3 WorldPos0; 
flat out int InstanceID; 

void main() 
    gl_Position = WVP * vec4(Position, 1.0); 
    TexCoord0 = TexCoord; 
    Normal0 = World * vec4(Normal, 0.0)).xyz; 
    WorldPos0 = World * vec4(Position, 1.0)).xyz; 
    InstanceID = gl_InstanceID
};


Fragment shader.

flat in int InstanceID;
...
uniform vec4 gColor[4];

...

void main() 
    vec3 Normal = normalize(Normal0); 
    vec4 TotalLight = CalcDirectionalLight(Normal); 

    for (int i = 0 ; i < gNumPointLights ; i++) { 
        TotalLight += CalcPointLight(gPointLights[i], Normal); 
    } 

    for (int i = 0 ; i < gNumSpotLights ; i++) { 
        TotalLight += CalcSpotLight(gSpotLights[i], Normal); 
    } 

    FragColor = texture(gColorMap, TexCoord0.xy) * TotalLight * gColor[InstanceID % 4];
};


Main render loop needs to transpose matrices (column-vector matrices).

Pipeline p;
p.SetCamera(m_pGameCamera->GetPos(), m_pGameCamera->GetTarget(), m_pGameCamera->GetUp());
p.SetPerspectiveProj(m_persProjInfo); 
p.Rotate(0.0f, 90.0f, 0.0f);
p.Scale(0.005f, 0.005f, 0.005f); 

Matrix4f WVPMatrics[NUM_INSTANCES];
Matrix4f WorldMatrices[NUM_INSTANCES];

for (unsigned int i = 0 ; i < NUM_INSTANCES ; i++) {
    Vector3f Pos(m_positions[i]);
    Pos.y += sinf(m_scale) * m_velocity[i];
    p.WorldPos(Pos); 
    WVPMatrics[i] = p.GetWVPTrans().Transpose();
    WorldMatrices[i] = p.GetWorldTrans().Transpose();
}

m_pMesh->Render(NUM_INSTANCES, WVPMatrics, WorldMatrices);


Buffer re-specification
This solution is to reallocate the buffer object before you start modifying it. This is termed buffer "orphaning". There are two ways to do it.

The first way is to call glBufferData with a NULL pointer, and the exact same size and usage hints it had before. This allows the implementation to simply reallocate storage for that buffer object under-the-hood. Since allocating storage is (likely) faster than the implicit synchronization, you gain significant performance advantages over synchronization. And since you passed NULL, if there wasn't a need for synchronization to begin with, this can be reduced to a no-op.

Instanced arrays
Normally, vertex attribute arrays are indexed based on the index buffer, or when doing array rendering, once per vertex from the start point to the end. However, when doing instanced rendering, it is often useful to have an alternative means of getting per-instance data than accessing it directly in the shader via a Uniform Buffer Object, a Buffer Texture, or some other means.
It is possible to have one or more attribute arrays indexed, not by the index buffer or direct array access, but by the instance count. This is done via this function:
void glVertexAttribDivisor(GLuint index​, GLuint divisor​);
The index is the attribute index to set. If divisor is zero, then the attribute acts like normal, being indexed by the array or index buffer. If divisor is non-zero, then the current instance is divided by this divisor, and the result of that is used to access the attribute array.
The "current instance" mentioned above starts at the base instance for instanced rendering, increasing by 1 for each instance in the draw call. Note that this is not how the gl_InstanceID is computed for Vertex Shaders; that is not affected by the base instance. If no base instance is specified, then the current instance starts with 0.
This is generally considered the most efficient way of getting per-instance data to the vertex shader. However, it is also the most resource-constrained method in some respects. OpenGL implementations usually offer a fairly restricted number of vertex attributes (16 or so), and you will need some of these for the actual per-vertex data. So that leaves less room for your per-instance data. While the number of instances can be arbitrarily large (unlike UBO arrays), the amount of per-instance data is much smaller.

However, that should be plenty for a quaternion orientation and a position, for a simple transformation. That would even leave one float (the position only needs to be 3D) to provide a fragment shader an index to access an Array Texture.

Matrix attributes
Attributes in GLSL can be of matrix types. However, our attribute binding functions only bind up to a dimensionality of 4. OpenGL solves this problem by converting matrix GLSL attributes into multiple attribute indices.
If you directly assign an attribute index to a matrix type, it implicitly takes up more than one attribute index. The number of attributes a matrix takes up depends on the number of columns of the matrix: a mat2 matrix will take 2, a mat2x4 matrix will take 2, while a mat4x2 will take 4. The size of each attribute is the number of rows of the matrix.
Each bound attribute in the VAO therefore fills in a single column, starting with the left-most and progressing right. Thus, if you have a 3x3 matrix, and you assign it to attribute index 3, it will naturally take attribute indices 3, 4, and 5. Each of these indices will be 3 elements in size. Attribute 3 is the first column, 4 is the second, and 5 is the last.
OpenGL will allocate locations for matrix attributes contiguously as above. So if you defined a 3x3 matrix, it will return one value, but the next two values are also valid, active attributes.

Double-precision matrices (where available) will take up twice as much space. So a dmat3x3 will take up 6 attribute indices, two for each column.

Matrix inputs take up one attribute index for every column. Array attributes take up one index per element, even if the array is a float and could have use up to 4 indices.
Double-precision input variables of double or dvec types always take up one attribute. Even if they are dvec4 .
These combine with each other. A mat2x4[2] array is broken up into four vec4 values, each of which is assigned an index. Thus, it takes up 4 indices; the first two indices specify the two columns of array index 0, and the next two indices specify the two columns of array index 1.
When an input requires multiple indices, it will always be assigned sequential indices starting from the given index. Consider:

layout(location = 3) in mat4 a_matrix;

a_matrix will be assigned attribute indices 3, 4, 5, and 6. This works regardless of what methods you use to assign vertex attribute indices to input variables.
Linking will fail if any index ranges collide. Thus, this will fail to link:

layout(location = 0) in mat4 a_matrix;
layout(location = 3) in vec4 a_vec;





Tuesday, April 21, 2015

Real-time smoke and fire simulation.

Input parameters:
- area
- gravity
- combustion (?)
- density (of surrounding medium)
- fluid buoyancy (to calc speed in opposite direction to gravity)
- turbulence (or vorticity)

Particle properties:
- temperature
- lifespan
- seed

Uniform temperature at vertex is interpolated and used by a fragment shader. So, temperature can be an attribute, updated each frame.

Sunday, March 29, 2015

Optimal use of std::ifstream to read into std::string

This is an exemplary bit of code to help read a file by std::ifstream and avoid needless buffer reallocations.
1. DataPath, returns a "Data" subdirectory inside application bundle. In Xcode to package resource files along with a bundle, add the resource directory to a project as a directory reference. Don't name it as "Resources", internal packaging system reserves that name (for whatever reason) and will throw an annoying "iOS Simulator failed to install the application" error.
So, I've chosen to scope resources inside a "Data" directory.
2. ReadFile, will read entire file content and return in a std::string. Will work for cross-platform file access, just paste in a .cpp file.


<FileSystem.hpp>

#include <string>


namespace FileSystem
{
    
    std::string DataPath();
    
    std::string ReadFile(const char* filePath);
    
}



<FileSystem.mm>

#import <Foundation/Foundation.h>
#include <iostream>
#include <fstream>
#import "FileSystem.hpp"


namespace FileSystem
{

    using namespace std;
    
    string DataPath()
    {
        string result;
        NSBundle* bundle = [NSBundle mainBundle];
        
        if (bundle == nil) {
            #ifdef DEBUG
                NSLog(@"Bundle is nil... which should never happen.");
            #endif
        } else {
            NSString* path = [bundle bundlePath];
            // Also, to get Documents directory:
            // path = [NSHomeDirectory() stringByAppendingString: @"/Documents/"];
            path = [NSString stringWithFormat: @"%@%s", path, "/Data/"];
            result = string([path UTF8String]);
        }
        
        return result;
    }
    
    string ReadFile(const char* filePath)
    {
        string result;
        
        ifstream ifs(filePath, ios::in | ios::binary | ios::ate);
        if (!ifs) {
            throw invalid_argument(string("Error opening '") + filePath + "'.");
        }
        
        auto fileSize = ifs.tellg();
        result.resize((string::size_type)fileSize);
        
        ifs.seekg(0, ios::beg);
        auto buf = &result[0];
        ifs.read(buf, (streamsize)fileSize);
        return result;
    }

}




Monday, February 3, 2014

Modal Views in iOS 7 Storyboards


Walkthrough to make a secondary scene in a storyboard act as an animated modal dialog, similar to the Alert view.


Prerequisites:

1. Create a single-view app project.
2. In Project Settings/General/Deployment Info make sure the storyboard name (Main.storyboard) appears in Main Interface popover.


3. Add/remove remove view controllers (VCs) to the storyboard as needed.
4. To make a VC the very first controller - click it to highlight blue, then in Attributes Inspector check the Initial Scene. This will set origin arrow.

5. Create a modal Manual Segue ("seg-way"). In the IB zoom out by double-click on an empty space. Then Ctrl-drag from the presenting VC to the modal VC. Select "modal" in a dialog.

6. To make sure the transition is animated select the segue, check the Animates attribute in the Attribute Inspector.


Now, to use the default animation provided by Xcode - do the following:

1. Add a new View Controller (VC), set it as a CustomClass/Class attribute in Identity Inspector for the presenting view (from-view). Add a button and a tap event handler to the presenting view.

//
//  ALYViewController.m
//

#import "ALYViewController.h"
#import "ALYZoomAnimator.h"

NSString *const MySegueID = @"MySegueID";

@interface ALYViewController ()
@property (strong, nonatomic) ALYZoomAnimator *zoomAnimator;

- (IBAction)showModalViewTapped:(id)sender;
@end


@implementation ALYViewController

- (IBAction)showModalViewTapped:(id)sender {
    [self performSegueWithIdentifier: MySegueID sender: nil];
}
@end

2. Do the same for the modal view, except the code will be dismissing this dialog.
//
//  ALYModalViewController.m
//

#import "ALYModalViewController.h"

@interface ALYModalViewController ()

- (IBAction)dismissTapped:(id)sender;
@end

@implementation ALYModalViewController

- (IBAction)dismissTapped:(id)sender {
    [self dismissViewControllerAnimated: YES completion: nil];
}
@end

3. Run the app. Click the button to reveal the modal dialog.


To add a custom transition with added benefit of controlling size and appearance of the modal dialog (for interactivity, cancellation, etc. in later posts), do the following:

1. Implement <UIViewControllerTransitioningDelegate> and <UIViewControllerAnimatedTransitioning> in a separate animator class. This will handle in/out transitions for a modal dialog. Unfortunately there is no context property to tell which transition is being initiated, in or out. One workaround is to record a VC being presented and then compare it against the to-VC of the transitionContext.

//
//  ALYZoomAnimator.h
//

#import <Foundation/Foundation.h>

@interface ALYZoomAnimator : NSObject <UIViewControllerTransitioningDelegate, UIViewControllerAnimatedTransitioning>

@end 

//
//  ALYZoomAnimator.m
//

#import "ALYZoomAnimator.h"

#define IN_DURATION 1.0
#define OUT_DURATION 0.3

@interface ALYZoomAnimator()
@property (weak, nonatomic) UIViewController *presentedVC;

@end


@implementation ALYZoomAnimator

// Returns true while the IN animation is active to reveal the modal sub-dialog.
- (BOOL) isBeingPresented: (id<UIViewControllerContextTransitioning>) transitionContext
{
 UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    return toVC == self.presentedVC;
}


#pragma mark - <UIViewControllerTransitioningDelegate>

- (id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source
{
    self.presentedVC = presented;
    return self;
}

- (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed
{
    return self;
}


#pragma mark - UIViewControllerAnimatedTransitioning

- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext
{
    return [self isBeingPresented: transitionContext] ? IN_DURATION : OUT_DURATION;
}

- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
    UIView *container = transitionContext.containerView;
 
 UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    UIView *fromView = fromVC.view;
    UIView *toView = toVC.view;
    
    CGRect cb = container.bounds;
    CGRect startFrame = CGRectMake(cb.size.width / 2, cb.size.height / 2 - 50, 0, 0);
 CGRect endFrame = CGRectInset(startFrame, -100, -100);
    UIView *snapshot;
    
 if ([self isBeingPresented: transitionContext]) {
        fromView.userInteractionEnabled = NO;
        fromView.tintColor = [UIColor grayColor];
        toView.frame = endFrame;
  snapshot = [toView snapshotViewAfterScreenUpdates:YES];
  snapshot.frame = startFrame;
        snapshot.alpha = 0.0;
        [container addSubview: snapshot];
        [UIView animateWithDuration: [self transitionDuration: transitionContext]
                              delay: 0
             usingSpringWithDamping: 500 initialSpringVelocity: 15
                            options: 0
                         animations: ^{
                             fromView.tintAdjustmentMode = UIViewTintAdjustmentModeDimmed;
                             snapshot.frame = endFrame;
                             snapshot.alpha = 1.0;
                         }
                         completion: ^(BOOL finished) {
                             toView.frame = endFrame;
                             [container addSubview: toView];
                             [snapshot removeFromSuperview];
                             [transitionContext completeTransition:YES];
                         }];
 } else {
  snapshot = [fromView snapshotViewAfterScreenUpdates:YES];
        snapshot.frame = endFrame;
        [container addSubview: snapshot];
        [fromView removeFromSuperview];
        [UIView animateWithDuration: [self transitionDuration: transitionContext]
                              delay: 0
             usingSpringWithDamping: 500 initialSpringVelocity: 15
                            options: 0
                         animations: ^{
                             toView.tintAdjustmentMode = UIViewTintAdjustmentModeNormal;
                             snapshot.frame = startFrame;
                             snapshot.alpha = 0.0;
                         }
                         completion: ^(BOOL finished) {
                             [snapshot removeFromSuperview];
                             toView.userInteractionEnabled = YES;
                             [transitionContext completeTransition:YES];
                         }];
 }
}

@end


2. Provide -prepareForSegue method in the presenting VC.

//
//  ALYViewController.m
//

#import "ALYViewController.h"
#import "ALYZoomAnimator.h"

NSString *const MySegueID = @"MySegueID";

@interface ALYViewController ()
@property (strong, nonatomic) ALYZoomAnimator *zoomAnimator;

- (IBAction)showModalViewTapped:(id)sender;
@end


@implementation ALYViewController

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if (![segue.identifier isEqualToString: MySegueID]) {
        return;
    }
    if (!self.zoomAnimator) {
        self.zoomAnimator = [[ALYZoomAnimator alloc] init];
    }
    
    [segue.destinationViewController setTransitioningDelegate: self.zoomAnimator];
    [segue.destinationViewController setModalPresentationStyle: UIModalPresentationCustom];
}

- (IBAction)showModalViewTapped:(id)sender {
    [self performSegueWithIdentifier: MySegueID sender: nil];
}
@end

3. Run the app. Observe the modal dialog animations, transparency, presenting view in the background providing a context to help users keep track of their position in app. This is unlike the normal transitions that will hide the presenting view.



Monday, December 30, 2013

My Git bits and patterns

Based on the excellent guide by Sam Livingston-Gray: http://think-like-a-git.net

1. Scout Pattern for testing a merge.


Switch to a branch to merge into:
$ git checkout feature_A

        I---J---K feature_B
       /
      F---G---H feature_A
     /
A---B---C---D---E master

Create and checkout a new branch:
$ git checkout -b test_merge

          I---J---K feature_B
         /
        /       L test_merge
       /       /
      F---G---H feature_A
     /
A---B---C---D---E master

Merge with the other branch:
$ git merge feature_B

          I---J---K feature_B
         /         \
        /       L---M test_merge
       /       /
      F---G---H feature_A
     /
A---B---C---D---E master

Resolve merge conflicts and test the merge.

If merge works, keep it and merge into the feature_A:
$ git checkout feature_A
$ git merge test_merge

If merge does not work, switch to feature_A (or "master") and delete the test_merge:
$ git checkout feature_A
$ git branch -D test_merge

To abort the merge:
$ git reset --hard
or
$ git reset --hard feature_A


2. Relative references for testing a merge.


This is an extension of the Scout Pattern, with no extra step to create a checkpoint.

Switch to a branch to merge into:
$ git checkout feature_A

        I---J---K feature_B
       /
      F---G---H feature_A
     /
A---B---C---D---E master

Merge with the other branch:
$ git merge feature_B

        I---J---K feature_B
       /         \
      F---G---H---L feature_A
     /
A---B---C---D---E master

Resolve merge conflicts and test the merge.

If merge works, just keep the feature_A, and do nothing.
If merge does not work, hard reset to a prior checkpoint:
$ git reset --hard HEAD^

        I---J---K feature_B
       /
      F---G---H feature_A
     /
A---B---C---D---E master

Note: the relative checkpoint syntax HEAD^, HEAD^^, HEAD~3, etc.

To abort the merge:
$ git reset --hard


3. Undo a commit with missing info, misspelled messages, etc.


Move to prior checkpoint. This leaves the working tree as it was before "reset" (all local changes since HEAD^ are preserved):
$ git reset --soft HEAD^

Edit and commit files:
$ git commit -a -c ORIG_HEAD

All of the above commands are practical and I would use them in most situations. I have yet to see a case to use the following command.


4. Rebase allows to "replay" part of checkin history at a different base.


So, having the following tree of checkins:

                I---J---K topic
               /
      F---G---H checkpoint
     /
A---B---C---D---E master

To "move" all related checkins, the following command will reapply G, H, I, J, K one-by-one, in order, at the new base "master":
$ git rebase master topic

                              I'---J'---K' topic
                             /
                  F'---G'---H' checkpoint
                 /
A---B---C---D---E master

Note: Those changes at the "topic" branch that were previously applied to "master" in some prior merges, will not be replayed by rebase. Checkins that are not part of the "topic's" history will remain unchanged (C, D, and E).

To specify a subrange of checkins to rebase from the "topic" branch, add "--onto <base>" parameter followed by a range ("checkpoint" to "topic"):
$ git rebase --onto master checkpoint topic

        F---G---H checkpoint
       /
      /           I'---J'---K' topic
     /           /
A---B---C---D---E master


Tuesday, December 3, 2013

FAR File Manager, Beyond Compare, Notepad++ etc. in OS X with Wine

Readjusting to a new platform takes time. For me the most painful departure was from FAR (File and Archive Manager), Beyond Compare (by Scooter Software) and some other tools.

Wine for Mac OS X helps mitigate transition. It wraps platform API (Darwin) into a subset of Win32 libraries, has a convenient installer by Mike Kroneberg, called WineBottler.
Wine is a much more efficient way to experience native Windows applications on a Mac without having to run a full Windows OS in a virtual machine. This saves time, resources and battery life. System resources, external Flash drives, web etc. are available to Wine applications.

I will show how to install FAR, Beyond Compare and how to use them.

1. Get WineBottler
Download it from http://winebottler.kronenberg.org. Open DMG file and drag both Wine.app and WineBottler.app to Applications.

2. Run WineBottler with FAR3 installer
Click the third tab, provide location of your Win32 application installer (or binaries if it's self contained). Here I am providing an MSI installer for FAR, the latest can be downloaded from http://www.farmanager.com (select x86 build).
There is not much else to configure. If you will want to use Notepad++ then make sure to select the "npp" from the Winetricks list (as shown).
Instead of using Win32 Notepad++ on a Mac, I'd suggest you take a look at the TextWrangler (http://www.barebones.com/products/textwrangler/). It is a free multi-document editor with contextual editing, familiar Xcode shortcuts (for example, Cmd+Opt+up-or-down to switch counterparts) etc.
Click "Install". This will walk you through installation steps. You will provide location for your FAR (or any other) app, then WineBottler will set up Wine support, you will see a FAR installer window where you select FAR options (I used defaults). After it finishes you'll find a new directory in user's "Library/Application Support/com.Far3OSX...":
This is where all binaries, Win32 emulation, and Windows-like file system structure will be found. If anything breaks during or after - simply delete the entire folder.

3. Copy and configure Beyond Compare
This is optional, but it is the goal of this post. If you already have Beyond Compare on a Windows machine - all you need is copy binaries and import configuration. Otherwise you can follow simple instructions from the last step, selecting Beyond Compare installer. WineBottler will produce another "/Users/user/Library/Application Support/com.Beyond Compare..." self-contained installation. Grab binaries from its "drive_c/Program Files".
Copy Beyond Compare files to FAR's "drive_c/Program Files". The result should look like this:
Before you will run Beyond Compare.app (or however you called it), , it will ask you to provide license. You can copy and paste any text now from your Mac to Wine-hosted application.

4. Run your FAR3OSX.app (or however you called it)
As mentioned in this thread you will need to edit a startwine file inside the FAR3OSX.app to be able to run it as a console. At the end of the file change "$WINEUSRPATH/bin/wine" to "$WINEUSRPATH/bin/wineconsole".
Run the app. To set default width and height of a console, right-click inside the window and select "Set Default". 


Now you can explore the local drives and manipulate files as you would in Windows. Note that Z: drive refers to the root of your Mac drive, so be cautious. C: drive is an alias to a directory "/Users/user/Library/Application Support/com.Far3OSX_.../drive_c".
Also note that Wine maps "Alt" key to a Command key on Mac keyboard. So instead of hitting "Alt+F1" or "Alt+F2" to change drives, use "Command+F1/F2".
FAR has lots of useful features, some of which are:

  • Built-in text/HEX viewer and editor (with color-coded keywords and familiar copy-paste).
  • Instant history for commands, folders, files. These are also used for line completion.
  • Built-in archiver with a shortcut.
  • Batch folder size calculation.
  • Powerful menu system. More on this next.

5. FAR3 User Menu
Press F2 to invoke the user-configurable menu. In this example I've configured it to list Beyond Compare and a Notepad++.
To edit a single entry hit F4, to open a menu file in an editor hit Command-F4. My menu file looks as follows. Note that I am using full paths to application executables. All the special symbols signify placeholders for the input from the two panels. To learn more about them - press F1 while in user menu.

1:  Beyond Compare 2 panels
    "C:\Program Files\Beyond Compare 2\bc2.exe" "!\" "!#!\"
2:  Beyond Compare 2 selected files
    "C:\Program Files\Beyond Compare 2\bc2.exe" !&
3:  Beyond Compare 2 files in 2 panels
    "C:\Program Files\Beyond Compare 2\bc2.exe" "!^!\!.!" "!#!\!.!"
--:  Notepad++
4:  Notepad++ [files] || [dir]
    "C:\npp\notepad++.exe" !&


The power of FAR now can be seen whenever you need to compare and sync folders or files. Just navigate left panel to one folder and the other panel to a different folder, press F2 and select to "Beyond Compare 2 panels".
Here I am syncing a folder on SanDisk Sansa MP3 player with a folder on a Flash drive.


On the first run Beyond Compare will ask you to register it, or to provide license. FAR and Notepad++ are free.

That's it. Of course there are similar tools available on Mac, but if you've purchased your Windows apps and would rather continue using them - I believe Wine is the best friend.




Sunday, November 24, 2013

C++ Refresher - Operator Precedence


Operator Precedence
(highlighted are the changes from R-value to L-value in C++ compared to C)
Operator      Description                    Result    Associativity

() Grouping exp N/A
() Function call rexp L-R [] Subscript lexp L-R . Structure member lexp L-R -> Structure pointer member lexp L-R ++ Postfix increment rexp L-R -- Postfix decrement rexp L-R
! Logical negate rexp R-L ~ One's complement rexp R-L + Unary plus rexp R-L - Unary minus rexp R-L ++ Prefix increment LEXP R-L -- Prefix decrement LEXP R-L * Indirection (dereference) lexp R-L & Address of rexp R-L sizeof Size in bytes rexp R-L
(type) Type conversion (cast) rexp R-L
* Multiplication rexp L-R / Division rexp L-R % Integer remainder (modulo) rexp L-R
+ Addition rexp L-R - Subtraction rexp L-R
<< Left shift rexp L-R >> Right shift rexp L-R
> Greater than rexp L-R >= Greater than or equal rexp L-R < Less than rexp L-R <= Less than or equal rexp L-R
== Equal to rexp L-R != Not equal to rexp L-R
& Bitwise AND rexp L-R
^ Bitwise exclusive OR rexp L-R
| Bitwise inclusive OR rexp L-R
&& Logical AND rexp L-R
|| Logical OR rexp L-R
?: Conditional LEXP N/A
= Assignment LEXP R-L += Add to LEXP R-L -= Subtract from LEXP R-L *= Multiply by LEXP R-L /= Divide by LEXP R-L %= Modulo by LEXP R-L <<= Shift left by LEXP R-L >>= Shift right by LEXP R-L &= AND with LEXP R-L ^= Exclusive OR with LEXP R-L |= Inclusive OR with LEXP R-L
, Comma rexp L-R


Common non-printing control characters

0 Null 7 Bell 8 Backspace 9 Tab 10 Line feed 13 Carriage return 26 End of file (Ctrl-Z) 27 [Esc] (Escape key) ASCII characters (only 32-127 are standard)
32 64 @ 96 ` 128 € 160   192 + 224   33 ! 65 A 97 a 129  161 ¡ 193 - 225 á 34 " 66 B 98 b 130 ‚ 162 ¢ 194 - 226 A 35 # 67 C 99 c 131 ƒ 163 £ 195 + 227 d 36 $ 68 D 100 d 132 „ 164 ¤ 196 - 228 O 37 % 69 E 101 e 133 … 165 ¥ 197 + 229 ¢ 38 & 70 F 102 f 134 † 166 ¦ 198 Ý 230 æ 39 ' 71 G 103 g 135 ‡ 167 § 199 Ý 231 “ 40 ( 72 H 104 h 136 ˆ 168 ¨ 200 + 232 ™ 41 ) 73 I 105 i 137 ‰ 169 ª 201 + 233 E 42 * 74 J 106 j 138 Š 170 ª 202 - 234 U 43 + 75 K 107 k 139 ‹ 171 « 203 - 235 „ 44 , 76 L 108 l 140 Œ 172 ¬ 204 Ý 236 8 45 - 77 M 109 m 141  173 ­ 205 - 237 ” 46 . 78 N 110 n 142 Ž 174 ® 206 + 238 † 47 / 79 O 111 o 143  175 ¯ 207 - 239 n 48 0 80 P 112 p 144  176 Ý 208 - 240 = 49 1 81 Q 113 q 145 ‘ 177 Ý 209 - 241 ñ 50 2 82 R 114 r 146 ’ 178 Ý 210 - 242 = 51 3 83 S 115 s 147 “ 179 Ý 211 + 243 = 52 4 84 T 116 t 148 ” 180 Ý 212 + 244 ( 53 5 85 U 117 u 149 • 181 Ý 213 + 245 ) 54 6 86 V 118 v 150 – 182 Ý 214 + 246 ö 55 7 87 W 119 w 151 — 183 + 215 + 247 ~ 56 8 88 X 120 x 152 ˜ 184 + 216 + 248 ø 57 9 89 Y 121 y 153 ™ 185 Ý 217 + 249 ú 58 : 90 Z 122 z 154 š 186 Ý 218 + 250 ú 59 ; 91 [ 123 { 155 › 187 + 219 Ý 251 v 60 < 92 \ 124 | 156 œ 188 + 220 _ 252 n 61 = 93 ] 125 } 157  189 + 221 Ý 253 ý 62 > 94 ^ 126 ~ 158 P 190 + 222 Ý 254 Ý 63 ? 95 _ 127 Ý 159 Ÿ 191 + 223 _ 255


%c - characters
%s - strings (NULL terminated C strings)
%d, %i - integers
%f - floating point
%g - floating point (minimum digits)
%e - scientific notation
%p - pointers (displays in hex)
%x - hexadecimal integers
%o - octal integers
%u - unsigned integers
%ld, %li - long integers
%lu - unsigned long integers
%hd, %hi - short integers
%hu - unsigned short integers

C Refresher - Operator Precedence


Operator Precedence
Operator      Description                    Result    Associativity

() Grouping exp N/A
() Function call rexp L-R [] Subscript lexp L-R . Structure member lexp L-R -> Structure pointer member lexp L-R ++ Postfix increment rexp L-R -- Postfix decrement rexp L-R
! Logical negate rexp R-L ~ One's complement rexp R-L + Unary plus rexp R-L - Unary minus rexp R-L ++ Prefix increment rexp R-L -- Prefix decrement rexp R-L * Indirection (dereference) lexp R-L & Address of rexp R-L sizeof Size in bytes rexp R-L
(type) Type conversion (cast) rexp R-L
* Multiplication rexp L-R / Division rexp L-R % Integer remainder (modulo) rexp L-R
+ Addition rexp L-R - Subtraction rexp L-R
<< Left shift rexp L-R >> Right shift rexp L-R
> Greater than rexp L-R >= Greater than or equal rexp L-R < Less than rexp L-R <= Less than or equal rexp L-R
== Equal to rexp L-R != Not equal to rexp L-R
& Bitwise AND rexp L-R
^ Bitwise exclusive OR rexp L-R
| Bitwise inclusive OR rexp L-R
&& Logical AND rexp L-R
|| Logical OR rexp L-R
?: Conditional rexp N/A
= Assignment rexp R-L += Add to rexp R-L -= Subtract from rexp R-L *= Multiply by rexp R-L /= Divide by rexp R-L %= Modulo by rexp R-L <<= Shift left by rexp R-L >>= Shift right by rexp R-L &= AND with rexp R-L ^= Exclusive OR with rexp R-L |= Inclusive OR with rexp R-L
, Comma rexp L-R

ASCII Characters

Common non-printing control characters

0 Null 7 Bell 8 Backspace 9 Tab 10 Line feed 13 Carriage return 26 End of file (Ctrl-Z) 27 [Esc] (Escape key) ASCII characters (only 32-127 are standard)
32 64 @ 96 ` 128 € 160   192 + 224   33 ! 65 A 97 a 129  161 ¡ 193 - 225 á 34 " 66 B 98 b 130 ‚ 162 ¢ 194 - 226 A 35 # 67 C 99 c 131 ƒ 163 £ 195 + 227 d 36 $ 68 D 100 d 132 „ 164 ¤ 196 - 228 O 37 % 69 E 101 e 133 … 165 ¥ 197 + 229 ¢ 38 & 70 F 102 f 134 † 166 ¦ 198 Ý 230 æ 39 ' 71 G 103 g 135 ‡ 167 § 199 Ý 231 “ 40 ( 72 H 104 h 136 ˆ 168 ¨ 200 + 232 ™ 41 ) 73 I 105 i 137 ‰ 169 ª 201 + 233 E 42 * 74 J 106 j 138 Š 170 ª 202 - 234 U 43 + 75 K 107 k 139 ‹ 171 « 203 - 235 „ 44 , 76 L 108 l 140 Œ 172 ¬ 204 Ý 236 8 45 - 77 M 109 m 141  173 ­ 205 - 237 ” 46 . 78 N 110 n 142 Ž 174 ® 206 + 238 † 47 / 79 O 111 o 143  175 ¯ 207 - 239 n 48 0 80 P 112 p 144  176 Ý 208 - 240 = 49 1 81 Q 113 q 145 ‘ 177 Ý 209 - 241 ñ 50 2 82 R 114 r 146 ’ 178 Ý 210 - 242 = 51 3 83 S 115 s 147 “ 179 Ý 211 + 243 = 52 4 84 T 116 t 148 ” 180 Ý 212 + 244 ( 53 5 85 U 117 u 149 • 181 Ý 213 + 245 ) 54 6 86 V 118 v 150 – 182 Ý 214 + 246 ö 55 7 87 W 119 w 151 — 183 + 215 + 247 ~ 56 8 88 X 120 x 152 ˜ 184 + 216 + 248 ø 57 9 89 Y 121 y 153 ™ 185 Ý 217 + 249 ú 58 : 90 Z 122 z 154 š 186 Ý 218 + 250 ú 59 ; 91 [ 123 { 155 › 187 + 219 Ý 251 v 60 < 92 \ 124 | 156 œ 188 + 220 _ 252 n 61 = 93 ] 125 } 157  189 + 221 Ý 253 ý 62 > 94 ^ 126 ~ 158 P 190 + 222 Ý 254 Ý 63 ? 95 _ 127 Ý 159 Ÿ 191 + 223 _ 255

Common printf formatting codes

%c - characters
%s - strings (NULL terminated C strings)
%d, %i - integers
%f - floating point
%g - floating point (minimum digits)
%e - scientific notation
%p - pointers (displays in hex)
%x - hexadecimal integers
%o - octal integers
%u - unsigned integers
%ld, %li - long integers
%lu - unsigned long integers
%hd, %hi - short integers
%hu - unsigned short integers