Source

kinect-viewer / KVRenderer.m

/*
 * Copyright 2010 Cliff L. Biffle.  All Rights Reserved.
 * Use of this source code is governed by the Apache License 2.0,
 * which can be found in the LICENSE file.
 */

#import "KVRenderer.h"
#import "utility.h"

@interface KVRenderer ()
- (void) fillStaticComponents;

@property(assign, nonatomic) double rayCastingTotal;
@property(assign, nonatomic) NSUInteger rayCastingCount;

@property(assign, nonatomic) double vertexPlacementTotal;
@property(assign, nonatomic) NSUInteger vertexPlacementCount;

@property GLuint depthTexture;
@property GLuint colorTexture;

- (void) renderAsPointsWithOptions: (NSDictionary *) options;
@end

@implementation KVRenderer

@synthesize rayCastingCount, rayCastingTotal, vertexPlacementCount, vertexPlacementTotal;
@synthesize depthTexture, colorTexture;

- init {
  if ((self = [super init])) {
    [self fillStaticComponents];
  }
  return self;
}

#pragma mark --- Implementation of KVSpaceModel

- (void) initGL {
  glGenTextures(1, &depthTexture);
  glBindTexture(GL_TEXTURE_2D, depthTexture);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

  glGenTextures(1, &colorTexture);
  glBindTexture(GL_TEXTURE_2D, colorTexture);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
}

- (void) setDepthSamples: (NSData *)data {
  NSTimeInterval start = [NSDate timeIntervalSinceReferenceDate];
  
  const uint16_t *sample = [data bytes];
  memcpy(&depthImage, sample, sizeof depthImage);
  
  // gcc 4.2.1 is not clever enough to turn raster two-dimensional
  // subscripting (e.g. ray[y][x]) into a single incremented induction
  // variable -- we wind up doing integer multiplications on every
  // use!  So, we do it by hand: thus |vidx|.
  int vidx = 0;
  
  // Cast them rays
  for (int y = 0; y < 480 - 1; y++) {
    for (int x = 0; x < 640 - 1; x++, vidx++) {
      vec3f_t here = {
        rays[vidx].x,
        rays[vidx].y,
        sample[vidx],
      };
      vec3f_t right = {
        rays[vidx + 1].x,
        rays[vidx + 1].y,
        sample[vidx + 1],
      };
      vec3f_t down = {
        rays[vidx + 640].x,
        rays[vidx + 640].y,
        sample[vidx + 640],
      };
      normals[vidx] = compute_normal(here, down, right);
    }
  }
  
  NSTimeInterval end = [NSDate timeIntervalSinceReferenceDate];
  rayCastingCount++;
  rayCastingTotal += end - start;
  
  if ((rayCastingCount & 0xF) == 0) {
    NSLog(@"Raycasting: latest %.03fµs mean %.03fµs",
          (end - start) * 1000000.,
          (rayCastingTotal / rayCastingCount) * 1000000.);
  }
}

- (void) setColorSamples: (NSData *)data {
  memcpy(&colorImage, [data bytes], sizeof colorImage);
}

- (void) drawInCurrentOpenGLContextWithOptions: (NSDictionary *) options {
  NSTimeInterval start = [NSDate timeIntervalSinceReferenceDate];

  glActiveTexture(GL_TEXTURE0);
  glBindTexture(GL_TEXTURE_2D, depthTexture);
  glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE16, 640, 480, 0, GL_LUMINANCE, GL_UNSIGNED_SHORT, &depthImage);
  
  glActiveTexture(GL_TEXTURE1);
  glBindTexture(GL_TEXTURE_2D, colorTexture);
  glTexImage2D(GL_TEXTURE_2D, 0, 3, 640, 480, 0, GL_RGB, GL_UNSIGNED_BYTE, &colorImage);
  
  [self renderAsPointsWithOptions: options];
  
  NSTimeInterval end = [NSDate timeIntervalSinceReferenceDate];
  vertexPlacementCount++;
  vertexPlacementTotal += end - start;
  
  if ((vertexPlacementCount & 0xF) == 0) {
    NSLog(@"Vertex placement: latest %.03fµs mean %.03fµs",
          (end - start) * 1000000.,
          (vertexPlacementTotal / vertexPlacementCount) * 1000000.);
  }
  
}

#pragma mark --- Internals

- (void) renderAsPointsWithOptions: (NSDictionary *) options {
  glColor3f(1, 1, 1);
  glNormal3f(0, 0, -1);
  glEnableClientState(GL_VERTEX_ARRAY);
  glVertexPointer(3, GL_FLOAT, 0, &rays);

  glEnableClientState(GL_NORMAL_ARRAY);
  glNormalPointer(GL_FLOAT, 0, &normals);
  
  glDrawArrays(GL_POINTS, 0, 640 * 480);
  
  glDisableClientState(GL_NORMAL_ARRAY);
  glDisableClientState(GL_VERTEX_ARRAY);
}

// We pre-fill the X and Y components with distance from the center of
// the image.  These values never make it to the rasterizer: they are
// merely input to the vertex shader that performs perspective correction.
- (void) fillStaticComponents {
  int vidx = 0;
  for (int y = 0; y < 480; y++) {
    for (int x = 0; x < 640; x++, vidx++) {
      rays[vidx].x = (x / 640.f);
      rays[vidx].y = (y / 480.f);
      rays[vidx].z = 4;
    }
  }
}

@end
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.