Drawing a sphere or other 3D shapes in C4?

527 views Asked by At

In Processing if I wanted to draw a globe and put a texture on it to create a 3D world it would be rather trivial. I'll add the code from a project I did where i placed tweets on a globe as well as had another texture map on top which was clouds. Is there some documentation someone can point me towards that would help me start trying to accomplish a similar output on the iPhone? I found some iOS snippets that helped me from the Programming 3D for the iPhone book. I'm trying to learn C4 and would like to approach the problem inside that framework. Thanks!

import processing.opengl.*;

PImage bg;
PImage texmap;
PImage clouds;
float cloudRotation = 0;


int sDetail       =  35;  // Default is 35
float rotationX   =   0;
float rotationY   =   0;
float velocityX   =   0;
float velocityY   =   0;
float globeRadius = 300;
float pushBack    =   0;


float[] cx, cz, sphereX, sphereY, sphereZ;
float sinLUT[];
float cosLUT[];
float SINCOS_PRECISION = 0.5f;
int SINCOS_LENGTH = int( 360.0 / SINCOS_PRECISION );




void setup()
{
  size( 640, 480, OPENGL );  
  texmap = loadImage( "world32k.jpg" );
  clouds = loadImage( "clouds.png" );
  initializeSphere( sDetail );
};




void draw()
{    
  background( 0 );            
  renderGlobe(); 
};




void renderGlobe() 
{
  pushMatrix();

    translate( width / 2.0, height / 2.0, pushBack );
    pushMatrix();

      noFill();
      //stroke( 255, 200 );
      //strokeWeight( 2 );
      smooth();

    popMatrix();
    lights();    
    pushMatrix();

      rotateX( radians(   0 - rotationX ));  
      rotateY( radians( 270 - rotationY ));
      fill( 200 );
      textureMode( IMAGE );
      texturedSphere( globeRadius, texmap, 255, false );

      pushMatrix();
      noStroke();
      rotateY( radians( cloudRotation += 0.08 ));
      texturedSphere( globeRadius + 20, clouds, 127, false );
      popMatrix();




          /////////////////////
         //                 //  
        //   Plot Points   //
       //                 //
      /////////////////////


      //  For our purposes we need to spin the globe by 1/4
      //  in other words, 90 degrees.

      rotateY( radians( 90 ));
      noStroke();
      fill( 255, 255, 0 );


      //  New York City

      pushMatrix();
      rotateY( radians( -73.967 ));  //  Longtitude 78.967 degress West  (negative)
      rotateX( radians(  40.783 ));  //  Latitude   40.783 degrees North (positive)
      translate( 0, 0, globeRadius * 0.6 );
      box( 4, 4, 100 );
      popMatrix();


      //  Paris

      pushMatrix();
      rotateY( radians(  2.3 ));  //  Longtitude 2.3 degress East  (positive)
      rotateX( radians( 48.8 ));  //  Latitude  48.8 degrees North (positive)
      translate( 0, 0, globeRadius * 0.6 );
      box( 4, 4, 100 );
      popMatrix();

      //  Dubai

      pushMatrix();
      rotateY( radians( 55.3 ));  //  Longitude 55.3 degrees East  (positive)
      rotateX( radians( 25.3 ));  //  Latitude  25.3 degrees North (positive)
      translate( 0, 0, globeRadius * 0.6 );
      box( 4, 4, 100 );
      popMatrix();


      //  Sydney

      pushMatrix();
      rotateY( radians( 151 ));  //  Longtitude 151 degress East  (positive)
      rotateX( radians( -34 ));  //  Latitude    34 degrees South (negative)
      translate( 0, 0, globeRadius * 0.6 );
      box( 4, 4, 100 );
      popMatrix();


      //  Seol

      pushMatrix();
      rotateY( radians( 127 ));  //  Longtitude 127 degress East  (positive)
      rotateX( radians(  37 ));  //  Latitude    37 degrees North (positive)
      translate( 0, 0, globeRadius * 0.6 );
      box( 4, 4, 100 );
      popMatrix();


      //  Santiago

      pushMatrix();
      rotateY( radians( -70 ));  //  Longtitude 70 degress West  (negative)
      rotateX( radians( -33 ));  //  Latitude   33 degrees South (negative)
      translate( 0, 0, globeRadius * 0.6 );
      box( 4, 4, 100 );
      popMatrix();


      //  Nairobi

      pushMatrix();
      rotateY( radians( 36 ));  //  Longtitude 36 degress East  (positive)
      rotateX( radians( -1 ));  //  Latitude    1 degrees South (negative)
      translate( 0, 0, globeRadius * 0.6 );
      box( 4, 4, 100 );
      popMatrix();



    popMatrix();
  popMatrix();
  rotationX += velocityX;
  rotationY += velocityY;
  velocityX *= 0.95;
  velocityY *= 0.95;


  //  Implements mouse control
  //  interaction will be inverse when sphere is upside down

  if( mousePressed )
  {
    velocityX += ( mouseY - pmouseY ) * 0.01;
    velocityY -= ( mouseX - pmouseX ) * 0.01;
  };
};




void initializeSphere( int res )
{
  sinLUT = new float[SINCOS_LENGTH];
  cosLUT = new float[SINCOS_LENGTH];

  for( int i = 0; i < SINCOS_LENGTH; i ++ )
  {
    sinLUT[i] = (float) Math.sin( i * DEG_TO_RAD * SINCOS_PRECISION );
    cosLUT[i] = (float) Math.cos( i * DEG_TO_RAD * SINCOS_PRECISION );
  };

  float delta = (float) SINCOS_LENGTH / res;
  float[] cx = new float[ res ];
  float[] cz = new float[ res ];


  // Calc unit circle in XZ plane

  for( int i = 0; i < res; i ++ )
  {
    cx[i] = -cosLUT[ (int) (i * delta) % SINCOS_LENGTH ];
    cz[i] =  sinLUT[ (int) (i * delta) % SINCOS_LENGTH ];
  };


  // Computing vertexlist vertexlist starts at south pole

  int vertCount = res * (res - 1) + 2;
  int currVert  = 0;


  //  Re-initialize arrays to store vertices

  sphereX = new float[ vertCount ];
  sphereY = new float[ vertCount ];
  sphereZ = new float[ vertCount ];
  float angle_step = (SINCOS_LENGTH*0.5f)/res;
  float angle = angle_step;


  //  Step along Y axis

  for( int i = 1; i < res; i ++ )
  {
    float curradius = sinLUT[ (int) angle % SINCOS_LENGTH ];
    float currY = -cosLUT[ (int) angle % SINCOS_LENGTH ];
    for( int j = 0; j < res; j ++ )
    {
      sphereX[ currVert    ] = cx[j] * curradius;
      sphereY[ currVert    ] = currY;
      sphereZ[ currVert ++ ] = cz[j] * curradius;
    };
    angle += angle_step;
  };
  sDetail = res;

};




//  Generic routine to draw textured sphere

void texturedSphere( float r, PImage t, int alpha, boolean showOutlines ) 
{
  fill( 255, alpha );

  int v1, v11, v2;
  r = (r + 240) * 0.33;
  beginShape( TRIANGLE_STRIP );
  texture( t );

  //tint(255,255,255,255);
  if( showOutlines )
  {
    strokeWeight( 3 );
    stroke( 255, 31 );
  };

  float iu = (float) (t.width  - 1) / (sDetail);
  float iv = (float) (t.height - 1) / (sDetail);
  float  u = 0, v = iv;
  for( int i = 0; i < sDetail; i ++ )
  {
    vertex( 0, -r, 0, u, 0 );
    vertex( sphereX[i]*r, sphereY[i]*r, sphereZ[i]*r, u, v );
    u += iu;
  };
  vertex( 0, -r, 0, u, 0 );
  vertex( sphereX[0]*r, sphereY[0]*r, sphereZ[0]*r, u, v );
  endShape();


  //  Middle rings

  int voff = 0;
  for( int i = 2; i < sDetail; i ++ )
  {
    v1 = v11 = voff;
    voff += sDetail;
    v2 = voff;
    u = 0;
    beginShape( TRIANGLE_STRIP );
    texture( t );
    for( int j = 0; j < sDetail; j ++ )
    {
      vertex( sphereX[v1]*r, sphereY[v1]*r, sphereZ[v1++]*r, u, v );
      vertex( sphereX[v2]*r, sphereY[v2]*r, sphereZ[v2++]*r, u, v + iv );
      u += iu;
    };


    //  Close each ring

    v1 = v11;
    v2 = voff;
    vertex( sphereX[v1]*r, sphereY[v1]*r, sphereZ[v1]*r, u, v );
    vertex( sphereX[v2]*r, sphereY[v2]*r, sphereZ[v2]*r, u, v + iv );
    endShape();
    v += iv;
  }
  u = 0;


  //  Add the northern cap

  beginShape( TRIANGLE_STRIP );
  texture( t );
  for( int i = 0; i < sDetail; i ++ )
  {
    v2 = voff + i;
    vertex( sphereX[v2]*r, sphereY[v2]*r, sphereZ[v2]*r, u, v );
    vertex( 0, r, 0, u, v + iv );
    u += iu;
  };
  vertex( 0, r, 0,u, v + iv );
  vertex( sphereX[voff]*r, sphereY[voff]*r, sphereZ[voff]*r, u, v );
  endShape();

};
1

There are 1 answers

2
C4 - Travis On

FIRST: I created a github project for this answer: GLExample4.6.3 that you can download and use to follow along.

When C4 was first developed an OpenGL ES 1 object, i.e. C4GL, was included in the framework. The recent development of the API has been on animation, interactivity and media with a reliance on Core Animation as the primary underlying framework. The C4GL object hasn't been updated in a while and there have been quite a few developments with iOS / GL in the last year and a half. For instance, there is GLKit.

That said, it is possible to do what you want (but you'll have to get your hands dirty with some OPENGL to make it happen).

In order to show that you CAN have interactive OpenGL objects in C4 I have looked to a tutorial from Ray Wenderlich that shows you how to have an interactive (rotating) 3D object.

I didn't touch much of the code from the RW example (only copying the contents of viewDidLoad into the init method).

To build a C4 app that will incorporate a rotating object I did the following:

  1. Download the example code from RW
  2. Create a new C4 app (I did this in Xcode 4.6.3)
  3. Copy HelloGLKitViewController files (.h + .m) into the C4 app
  4. Copy tile_floor.png into the C4 app
  5. Copy the contents of viewDidLoad in HelloGLKitViewController.m to the initWithNibName:bundle:
  6. Add GLKit framework to the C4 app project from the Build Phases tab of

Next, I changed the C4Workspace.m look like the following code block

#import "C4WorkSpace.h"
#import <GLKit/GLKit.h>
#import "HelloGLKitViewController.h"

@interface C4WorkSpace ()
@property (readwrite, strong) GLKView *glView;
@property (readwrite, strong) HelloGLKitViewController *glViewController;
@end

@implementation C4WorkSpace

-(void)setup {
    _glViewController = [[HelloGLKitViewController alloc] initWithNibName:nil bundle:nil];
    _glViewController.view.frame = CGRectMake(10,10,self.canvas.width-20,self.canvas.height-20);
    [self.canvas addSubview:_glViewController.view];
}

So, to continue with your project / question... A good place to start for you is to look at the HelloGLKitViewController.m file to do the following:

  1. Change the cube to a sphere (I'm not a GL wiz, but I'm guessing you'll have to change the vertices at the top of the file).
  2. Remap the texture to the new sphere
  3. Probably get rid of the flashing red!