Highlight highscore using draw function - objective-c

I've implemented a highscore layer and now I want to highlight a new entry in the highscore. This is my current draw function but it doesn't work and gives this error multiple times:
OpenGL error 0x0501 in -[CCSprite draw] 530
Draw function:
- (void)draw {
[super draw];
if(currentScorePosition < 0) return;
ccDrawColor4F(0.0f, 0.0f, 0.0f, 0.2f);
float w = 320.0f;
float h = 27.0f;
float x = (320.0f - w) / 2.0f;
float y = 359.0f - currentScorePosition * h;
GLfloat vertices[4][2];
GLubyte indices[4] = { 0, 1, 3, 2 };
vertices[0][0] = x; vertices[0][1] = y;
vertices[1][0] = x+w; vertices[1][1] = y;
vertices[2][0] = x+w; vertices[2][1] = y+h;
vertices[3][0] = x; vertices[3][1] = y+h;
ccGLEnableVertexAttribs( kCCVertexAttribFlag_Position );
kmGLPushMatrix();
glVertexAttribPointer( currentScorePosition, 2, GL_FLOAT, GL_FALSE, vertices, 0 );
glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, indices);
kmGLPopMatrix();
ccDrawColor4F(1.0f, 1.0f, 1.0f, 1.0f);
}

Instead of manual openGL call to draw primitive, use Cocos2d calls.
void ccDrawSolidPoly( const CGPoint *poli, NSUInteger numberOfPoints, ccColor4F color );
For example, Here is my custom draw:
-(void) draw {
CGPoint vertices[16];
vertices[0] = ccp(0,radius);
vertices[1] = ccp(0,radius*(1-kappa));
vertices[2] = ccp(radius*(1-kappa),0);
vertices[3] = ccp(radius,0);
vertices[4] = ccp(size.width-radius,0);
vertices[5] = ccp(size.width-radius*(1-kappa),0);
vertices[6] = ccp(size.width,radius*(1-kappa));
vertices[7] = ccp(size.width,radius);
vertices[8] = ccp(size.width,size.height - radius);
vertices[9] = ccp(size.width,size.height - radius*(1-kappa));
vertices[10] = ccp(size.width-radius*(1-kappa),size.height);
vertices[11] = ccp(size.width-radius,size.height);
vertices[12] = ccp(radius,size.height);
vertices[13] = ccp(radius*(1-kappa),size.height);
vertices[14] = ccp(0,size.height-radius*(1-kappa));
vertices[15] = ccp(0,size.height-radius);
CGPoint polyVertices[4*cornerSegments+1];
appendCubicBezier(0*cornerSegments,polyVertices,vertices[0], vertices[1], vertices[2], vertices[3], cornerSegments);
appendCubicBezier(1*cornerSegments,polyVertices,vertices[4], vertices[5], vertices[6], vertices[7], cornerSegments);
appendCubicBezier(2*cornerSegments,polyVertices,vertices[8], vertices[9], vertices[10], vertices[11], cornerSegments);
appendCubicBezier(3*cornerSegments,polyVertices,vertices[12], vertices[13], vertices[14], vertices[15], cornerSegments);
polyVertices[4*cornerSegments] = vertices[0];
CCNode *node=[self getChildByTag:13435];
if(!node)
{
CCDrawNode *draw = [[[CCDrawNode alloc] init] autorelease];
[draw drawPolyWithVerts:polyVertices count:4*cornerSegments fillColor:ccc4f(fillColor.r, fillColor.g, fillColor.b, fillColor.a) borderWidth:2.0 borderColor:ccc4f(1.0, 0.5, 0.5, 0.8)];
[self addChild:draw z:0 tag:13435];
}
}

Related

OpenGL VBO Sphere Texture loading not working

I need to draw and texture a sphere. The project I am working on will involve a considerable amount of graphics which led me down the route of using VBO's.
I'm currently experiencing trouble trying to texture the sphere and all attempts have led me to a solid shaded sphere each time - with no visible texture. I am most likely doing something silly - but after many attempts, I am no further into understanding whether the problem is because of the texture loading, bad U/V Texture coordinates or using the wrong shaders..
Below is a copy of all of the source code.
//
//
// Copyright (c) 2013 Andy Ward. All rights reserved.
//
#import "SphereRenderer.h"
#import "shaderUtil.h"
#import "fileUtil.h"
#import "debug.h"
//#import <GLKit/GLKit.h>
// Shaders
enum {
PROGRAM_LIGHTING,
PROGRAM_PASSTHRU,
NUM_PROGRAMS
};
enum {
UNIFORM_MVP,
UNIFORM_MODELVIEW,
UNIFORM_MODELVIEWIT,
UNIFORM_LIGHTDIR,
UNIFORM_AMBIENT,
UNIFORM_DIFFUSE,
UNIFORM_SPECULAR,
UNIFORM_SHININESS,
UNIFORM_CONSTANT_COLOR,
NUM_UNIFORMS
};
enum {
ATTRIB_VERTEX,
ATTRIB_COLOR,
ATTRIB_NORMAL,
NUM_ATTRIBS
};
typedef struct {
char *vert, *frag;
GLint uniform[NUM_UNIFORMS];
GLuint id;
} programInfo_t;
programInfo_t program[NUM_PROGRAMS] = {
{ "lighting.vsh", "color.fsh" }, // PROGRAM_LIGHTING
{ "color.vsh", "color.fsh" }, // PROGRAM_PASSTHRU
};
typedef struct
{
float x;
float y;
float z;
float nx;
float ny;
float nz;
float u;
float v;
float r;
float g;
float b;
float a;
GLbyte padding[16];
} Vertex;
static float lightDir[3] = { 0.8, 4.0, 1.0 };
static float ambient[4] = { 0.35, 0.35, 0.35, 0.35 };
static float diffuse[4] = { 1.0-0.35, 1.0-0.35, 1.0-0.35, 1.0 };
static float specular[4] = { 0.8, 0.8, 0.8, 1.0 };
static float shininess = 8;
#implementation SphereRenderer
- (id)init
{
if (self = [super init])
{
angleDelta = -0.05f;
scaleFactor = 7; //max = 1025
r = 350; //scaleFactor * 48.0f;
//maxValue = 1025 * 48.0f;
xVelocity = 1.5f;
yVelocity = 0.0f;
xPos = r*2.0f;
yPos = r*3.0f;
// normalize light dir
lightDirNormalized = GLKVector3Normalize(GLKVector3MakeWithArray(lightDir));
projectionMatrix = GLKMatrix4Identity;
[self LoadTexture];
[self generateSphereData];
[self setupShaders];
}
return self;
}
- (void)makeOrthographicForWidth:(CGFloat)width height:(CGFloat)height
{
projectionMatrix = GLKMatrix4MakeOrtho(0, width, 0, height, -50000.0f, 2000.0f);
}
-(void)generateSphereData
{
#define PI 3.141592654
#define TWOPI 6.283185308
int x;
int index = 0;
float v1x, v1y, v1z;
float v2x, v2y, v2z;
float d;
int theta, phi;
float theta0, theta1;
float phi0, phi1;
Vertex quad[4];
Vertex *sphereData = malloc( 128 * 256* 6 * sizeof( Vertex ) );
float delta = M_PI / 128;
// 32 vertical segments
for(theta = 0; theta < 128; theta++)
{
theta0 = theta*delta;
theta1 = (theta+1)*delta;
// 64 horizontal segments
for(phi = 0; phi < 256; phi++)
{
phi0 = phi*delta;
phi1 = (phi+1)*delta;
// Generate 4 points per quad
quad[0].x = r * sin(theta0) * cos(phi0);
quad[0].y = r * cos(theta0);
quad[0].z = r * sin(theta0) * sin(phi0);
quad[0].u = (float)theta / (float)128;
quad[0].v = (float)phi / (float)256;
quad[1].x = r * sin(theta0) * cos(phi1);
quad[1].y = r * cos(theta0);
quad[1].z = r * sin(theta0) * sin(phi1);
quad[1].u = (float)theta / (float)128;
quad[1].v = (float)(phi + 1) / (float)256;
quad[2].x = r * sin(theta1) * cos(phi1);
quad[2].y = r * cos(theta1);
quad[2].z = r * sin(theta1) * sin(phi1);
quad[2].u = (float)(theta + 1)/ (float)128;
quad[2].v = (float)(phi + 1) / (float)256;
quad[3].x = r * sin(theta1) * cos(phi0);
quad[3].y = r * cos(theta1);
quad[3].z = r * sin(theta1) * sin(phi0);
quad[3].u = (float)(theta + 1) / (float)128;
quad[3].v = (float)phi / (float)256;
// Generate the normal
if(theta >= 4)
{
v1x = quad[1].x - quad[0].x;
v1y = quad[1].y - quad[0].y;
v1z = quad[1].z - quad[0].z;
v2x = quad[3].x - quad[0].x;
v2y = quad[3].y - quad[0].y;
v2z = quad[3].z - quad[0].z;
}
else
{
v1x = quad[0].x - quad[3].x;
v1y = quad[0].y - quad[3].y;
v1z = quad[0].z - quad[3].z;
v2x = quad[2].x - quad[3].x;
v2y = quad[2].y - quad[3].y;
v2z = quad[2].z - quad[3].z;
}
quad[0].nx = ( v1y * v2z ) - ( v2y * v1z );
quad[0].ny = ( v1z * v2x ) - ( v2z * v1x );
quad[0].nz = ( v1x * v2y ) - ( v2x * v1y );
d = 1.0f/sqrt(quad[0].nx*quad[0].nx +
quad[0].ny*quad[0].ny +
quad[0].nz*quad[0].nz);
quad[0].nx *= d;
quad[0].ny *= d;
quad[0].nz *= d;
// Generate the color - This was for testing until I have the textures loading...
if((theta ^ phi) & 1)
{
quad[0].r = 0.0f;
quad[0].g = 0.0f;
quad[0].b = 0.0f;
quad[0].a = 0.0f;
}
else
{
quad[0].r = 0.0f;
quad[0].g = 0.0f;
quad[0].b = 0.0f;
quad[0].a = 0.0f;
}
// Replicate vertex info.
for(x = 1; x < 4; x++)
{
quad[x].nx = quad[0].nx;
quad[x].ny = quad[0].ny;
quad[x].nz = quad[0].nz;
quad[x].r = quad[0].r;
quad[x].g = quad[0].g;
quad[x].b = quad[0].b;
quad[x].a = quad[0].a;
}
// Store the vertices in two triangles. We are drawing everything as triangles.
sphereData[index++] = quad[0];
sphereData[index++] = quad[1];
sphereData[index++] = quad[2];
sphereData[index++] = quad[0];
sphereData[index++] = quad[3];
sphereData[index++] = quad[2];
}
}
// Create the VAO
glGenVertexArrays(1, &vaoId);
glBindVertexArray(vaoId);
// Create a VBO buffer
glGenBuffers(1, &vboId);
glBindBuffer(GL_ARRAY_BUFFER, vboId);
glBufferData(GL_ARRAY_BUFFER, 128 * 256 * 6 * sizeof(Vertex), NULL, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, 128 * 256 * 6 * sizeof(Vertex), sphereData);
// set the colors - left as it's great for debugging
glEnableVertexAttribArray(ATTRIB_COLOR);
glVertexAttribPointer(ATTRIB_COLOR, 4, GL_FLOAT, GL_TRUE, sizeof(Vertex), (GLubyte *)(uintptr_t)offsetof(Vertex,r));
// set the normals
glEnableVertexAttribArray(ATTRIB_NORMAL);
glVertexAttribPointer(ATTRIB_NORMAL, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLubyte *)(uintptr_t)offsetof(Vertex,nx));
// set the texture
glEnableVertexAttribArray(1);
glError();
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLubyte *)(uintptr_t)offsetof(Vertex,u));
glError();
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
// set the positions
glEnableVertexAttribArray(ATTRIB_VERTEX);
glVertexAttribPointer(ATTRIB_VERTEX, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLubyte *)(uintptr_t)offsetof(Vertex,x));
//We need to free as we used malloc
free(sphereData);
}
-(void)LoadTexture
{
NSURL *url = nil;
CGImageSourceRef src;
CGImageRef image;
CGContextRef context = nil;
CGColorSpaceRef colorSpace;
GLubyte *data;
GLsizei width, height;
// NSImage* image = [NSImage imageNamed:#"World-satellite-map.png"];
NSBundle *bundle = [NSBundle bundleWithIdentifier: #"Award.WeatherEye3D"];
NSString *bundleRoot = [bundle pathForImageResource:#"World-satellite-map.png"];
url = [NSURL fileURLWithPath: bundleRoot];
src = CGImageSourceCreateWithURL((CFURLRef)url, NULL);
if (!src) {
NSLog(#"No image");
// free(data);
return;
}
image = CGImageSourceCreateImageAtIndex(src, 0, NULL);
CFRelease(src);
width = CGImageGetWidth(image);
height = CGImageGetHeight(image);
data = (GLubyte*) calloc(width * height * 4, sizeof(GLubyte));
colorSpace = CGColorSpaceCreateDeviceRGB();
context = CGBitmapContextCreate(data, width, height, 8, 4 * width, colorSpace, kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host);
CGColorSpaceRelease(colorSpace);
// Core Graphics referential is upside-down compared to OpenGL referential
// Flip the Core Graphics context here
// An alternative is to use flipped OpenGL texture coordinates when drawing textures
CGContextTranslateCTM(context, 0.0, height);
CGContextScaleCTM(context, 1.0, -1.0);
// Set the blend mode to copy before drawing since the previous contents of memory aren't used. This avoids unnecessary blending.
CGContextSetBlendMode(context, kCGBlendModeCopy);
CGContextDrawImage(context, CGRectMake(0, 0, width, height), image);
CGContextRelease(context);
CGImageRelease(image);
glGenTextures(1, &texture);
glGenBuffers(1, &pboId);
// Bind the texture
glBindTexture(GL_TEXTURE_2D, texture);
// Bind the PBO
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pboId);
// Upload the texture data to the PBO
glBufferData(GL_PIXEL_UNPACK_BUFFER, width * height * 4 * sizeof(GLubyte), data, GL_STATIC_DRAW);
// Setup texture parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
// OpenGL likes the GL_BGRA + GL_UNSIGNED_INT_8_8_8_8_REV combination
// Use offset instead of pointer to indictate that we want to use data copied from a PBO
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, 0);
// We can delete the application copy of the texture data now
free(data);
glBindTexture(GL_TEXTURE_2D, 0);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
}
- (void)setupShaders
{
//This code has been lifted from an example.
for (int i = 0; i < NUM_PROGRAMS; i++)
{
char *vsrc = readFile(pathForResource(program[i].vert));
char *fsrc = readFile(pathForResource(program[i].frag));
GLsizei attribCt = 0;
GLchar *attribUsed[NUM_ATTRIBS];
GLint attrib[NUM_ATTRIBS];
GLchar *attribName[NUM_ATTRIBS] = {
"inVertex", "inColor", "inNormal",
};
const GLchar *uniformName[NUM_UNIFORMS] = {
"MVP", "ModelView", "ModelViewIT", "lightDir", "ambient", "diffuse", "specular", "shininess", "constantColor",
};
// auto-assign known attribs
for (int j = 0; j < NUM_ATTRIBS; j++)
{
if (strstr(vsrc, attribName[j]))
{
attrib[attribCt] = j;
attribUsed[attribCt++] = attribName[j];
}
}
glueCreateProgram(vsrc, fsrc,
attribCt, (const GLchar **)&attribUsed[0], attrib,
NUM_UNIFORMS, &uniformName[0], program[i].uniform,
&program[i].id);
free(vsrc);
free(fsrc);
// set constant uniforms
glUseProgram(program[i].id);
if (i == PROGRAM_LIGHTING)
{
// Set up lighting stuff used by the shaders
glUniform3fv(program[i].uniform[UNIFORM_LIGHTDIR], 1, lightDirNormalized.v);
glUniform4fv(program[i].uniform[UNIFORM_AMBIENT], 1, ambient);
glUniform4fv(program[i].uniform[UNIFORM_DIFFUSE], 1, diffuse);
glUniform4fv(program[i].uniform[UNIFORM_SPECULAR], 1, specular);
glUniform1f(program[i].uniform[UNIFORM_SHININESS], shininess);
}
else if (i == PROGRAM_PASSTHRU)
{
glUniform4f(program[i].uniform[UNIFORM_CONSTANT_COLOR], 0.0f,0.0f,0.0f,0.4f);
}
}
glError();
}
- (void)update
{
yPos = 400;
xPos = 375;
}
- (void)render
{
GLKMatrix4 modelViewMatrix, MVPMatrix, modelViewMatrixIT;
GLKMatrix3 normalMatrix;
glBindVertexArray(vaoId);
// glBindTexture(GL_TEXTURE, texture);
// Draw "shadow"
/* glUseProgram(program[PROGRAM_PASSTHRU].id);
glEnable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA_SATURATE, GL_ONE_MINUS_SRC_ALPHA);
*/
/*// Make the "shadow" move around a bit. This is not a real shadow projection.
GLKVector3 pos = GLKVector3Normalize(GLKVector3Make(xPos, yPos, -100.0f));
modelViewMatrix = GLKMatrix4MakeTranslation(xPos + (pos.v[0]-lightDirNormalized.v[0])*20.0,
yPos + (pos.v[1]-lightDirNormalized.v[1])*10.0,
-800.0f);
modelViewMatrix = GLKMatrix4Rotate(modelViewMatrix, -16.0f, 0.0f, 0.0f, 1.0f);
modelViewMatrix = GLKMatrix4Rotate(modelViewMatrix, angle, 0.0f, 1.0f, 0.0f);
modelViewMatrix = GLKMatrix4Scale(modelViewMatrix, 1.05f, 1.05f, 1.05f);
MVPMatrix = GLKMatrix4Multiply(projectionMatrix, modelViewMatrix);
glUniformMatrix4fv(program[PROGRAM_PASSTHRU].uniform[UNIFORM_MVP], 1, GL_FALSE, MVPMatrix.m);
//Draw the shadow arrays
glDrawArrays(GL_TRIANGLES, 0, 32*64*6);
*/
// Draw Sphere
glUseProgram(program[PROGRAM_LIGHTING].id);
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glDepthFunc(GL_LESS);
glDisable(GL_BLEND);
glCullFace(GL_BACK);
glFrontFace(GL_CCW);
glEnable(GL_CULL_FACE);
// ModelView
modelViewMatrix = GLKMatrix4MakeTranslation(xPos, yPos, -200.0f); // was -100
//modelViewMatrix = GLKMatrix4Rotate(modelViewMatrix, -0.01f, 0.0f, 0.0f, 0.01f);
// modelViewMatrix = GLKMatrix4Rotate(modelViewMatrix, angle, 0.0f, 1.0f, 0.0f);
glUniformMatrix4fv(program[PROGRAM_LIGHTING].uniform[UNIFORM_MODELVIEW], 1, GL_FALSE, modelViewMatrix.m);
// MVP
MVPMatrix = GLKMatrix4Multiply(projectionMatrix, modelViewMatrix);
glUniformMatrix4fv(program[PROGRAM_LIGHTING].uniform[UNIFORM_MVP], 1, GL_FALSE, MVPMatrix.m);
// ModelViewIT (normal matrix)
bool success;
modelViewMatrixIT = GLKMatrix4InvertAndTranspose(modelViewMatrix, &success);
if (success) {
normalMatrix = GLKMatrix4GetMatrix3(modelViewMatrixIT);
glUniformMatrix3fv(program[PROGRAM_LIGHTING].uniform[UNIFORM_MODELVIEWIT], 1, GL_FALSE, normalMatrix.m);
}
glDrawArrays(GL_TRIANGLE_STRIP, 0, 128*256*6 ); // Value needs changing for number of triangles...
glUseProgram(0);
glError();
}
- (void)dealloc
{
if (vboId) {
glDeleteBuffers(1, &vboId);
vboId = 0;
}
if (vaoId) {
glDeleteVertexArrays(1, &vaoId);
vaoId = 0;
}
if (vertexShader) {
glDeleteShader(vertexShader);
vertexShader = 0;
}
if (fragmentShader) {
glDeleteShader(fragmentShader);
fragmentShader = 0;
}
if (shaderProgram) {
glDeleteProgram(shaderProgram);
shaderProgram = 0;
}
[super dealloc];
}
#end
Lighting.vsh : -
#version 150
in vec4 inVertex, inColor;
in vec3 inNormal;
out vec4 color;
uniform mat4 MVP, ModelView;
uniform mat3 ModelViewIT;
uniform vec3 lightDir;
uniform vec4 ambient, diffuse, specular;
uniform float shininess;
void main()
{
// transform position to clip space
gl_Position = MVP * inVertex;
// transform position to eye space
vec3 eyePosition = vec3(ModelView * inVertex);
// transform normal to eye space (normalization skipped here: inNormal already normalized, matrix not scaled)
vec3 eyeNormal = ModelViewIT * inNormal;
// directional light ambient and diffuse contribution (lightDir alreay normalized)
float NdotL = max(dot(eyeNormal, lightDir), 0.0);
vec4 lightColor = ambient + diffuse * NdotL;
if (NdotL > 0.0)
{
// half angle
vec3 H = normalize(lightDir - normalize(eyePosition));
// specular contribution
float NdotH = max(dot(eyeNormal, H), 0.0);
lightColor += specular * pow(NdotH, shininess);
}
// apply directional light color and saturate result
// to match fixed function behavior
color = min(inColor * lightColor, 1.0);
}
color.vsh : -
#version 150
in vec4 inVertex;
out vec4 color;
uniform mat4 MVP;
uniform vec4 constantColor;
void main()
{
gl_Position = MVP * inVertex;
color = constantColor;
}
Color.fsh: -
#version 150
in vec4 color;
out vec4 fragColor;
void main()
{
fragColor = color;
}
For texture loading I always double check the modes I'm using.
For your shaders I would check the #version of vertex and fragment shaders and make sure it plays nicely with whatever version of OpenGL you have installed or whatever your video card supports. I used to do a lot with JOGL and whenever I used #version 330 instead of #version 400 it was because my video card wasn't one of the newest models at the time and didn't support any shader beyond 330. There is actually quite some difference between versions 150 and 400 so if you are doing anything more advanced in your GL code than what your shaders can support, your textures won't load. (i.e. there was a major change in OpenGL around there where it was no longer fixed function pipeline, it was then all programmable pipeline and therefore you had much more control at the cost of having to do more work....like write your own VBO, heh)
There are also certain functions in GLSL that are different from version to version and when you are going that far back to 150, many of the newer ones won't be recognized.
Here is a good reference for shader language and what versions of OpenGL they are compatible with http://en.wikipedia.org/wiki/OpenGL_Shading_Language. I know it's just wiki, but all the version mappings on there look correct.
Also, I always had to check the direction of my normals. If they are upside down or in the opposite direction they're supposed to be (like pointing inward instead of outward) then your lighting and textures also won't work.
Here's an example of a shader I wrote a while back before I started using the newer shader versions:
v.glsl
#version 130
in vec4 vPosition;
in vec4 vColor;
in vec3 vNormal;
in vec2 vTexCoord;
out vec4 color;
out vec3 E,L,N;
out vec2 texCoord;
uniform vec4 LightPosition;
uniform vec4 Projection, Model, View;
void main() {
vec3 pos = (Model * vPosition).xyz;
E = normalize((View * vec4(0,0,0,1)).xyz-pos);
//camera eye
L = normalize(LightPosition.xyz - pos);
N = normalize(Model * vec4(vNormal, 0.0)).xyz; //set normal vector
gl_Position = Projection * View * Model * vPosition; //view mode: Projection
texCoord = vTextCoord; //output vector of texture coordinates
color = vColor; //output vector that tells you the color of each vertex
}
f.glsl
#version 130
in vec4 color;
in vec2 texCoord;
in vec3 N,L,E;
out vec4 fColor;
uniform sampler2D texture;
uniform vec4 GlobalAmbient, AmbientProduct, DiffuseProduct, SpecularProduct;
uniform vec3 LightDirection;
uniform float Shininess, CutoffAngle, LightIntensity;
void main() {
vec3 D, H;
//process the spotlight
D = normalize(LightDirection);
H = normalize(L+E); //normalize the sum of the Light and Camera (Eye) vectors
vec4 ambient = vec4(0,0,0,0);
vec4 diffuse = vec4(0,0,0,1);
vec4 specular = vec4(0,0,0,1);
vec4 color = vec4(0,0,0,0);
//spot coefficient
float Kc = LightIntensity * max(dot(D,-L)-CutoffAngle,0.0);
//ambient coefficient
ambient = (Kc*AmbientProduct) + ambient + GlobalAmbient;
//diffuse coefficient
float Kd = max(dot(L,N), 0.0);
//diffuse component
diffuse = Kc * Kd * DiffuseProduct + diffuse;
//specular coefficient
float Ks = pow(max(dot(E,H), 0.0), Shininess);
//specular component
if(dot(L,N) >= 0.0) {
specular = Kc * Ks * SpecularProduct + specular;
}
fColor = (color + ambient + diffuse + specular) * texture2D(texture, texCoord);
fColor.a = 1.0; //fully opaque
}
I'll take a look at this some more when I get home because I love graphics. Now again, this shader code talks to Java code (using JOGL libs) so it will be done differently in Objective C, but the ideas are all the same.
Also check the order of your gl function calls - that can make a difference in many cases.
In ObjC I'd imagine you'd hand over your pixel data like this:
- (GLuint)setupTexture:(NSString *)fileName {
CGImageRef spriteImage = [UIImage imageNamed:fileName].CGImage;
if (!spriteImage) {
NSLog(#"Failed to load image %#", fileName);
exit(1);
}
size_t width = CGImageGetWidth(spriteImage);
size_t height = CGImageGetHeight(spriteImage);
GLubyte * spriteData = (GLubyte *) calloc(width*height*4, sizeof(GLubyte));
CGContextRef spriteContext = CGBitmapContextCreate(spriteData, width, height, 8, width*4,
CGImageGetColorSpace(spriteImage), kCGImageAlphaPremultipliedLast);
CGContextDrawImage(spriteContext, CGRectMake(0, 0, width, height), spriteImage);
CGContextRelease(spriteContext);
GLuint texName;
glGenTextures(1, &texName);
glBindTexture(GL_TEXTURE_2D, texName);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData);
free(spriteData);
return texName;
}

Box2d: Elastic rope takes time to get back to its initial position

I am creating a rubber band in Box2d. Here is my code.
// init physics
[self initPhysics];
// Create ball body
CCSprite *ball = [CCSprite spriteWithFile:#"rubberband.png"];
ball.position = ccp(100, 100);
ball.tag = 1;
// [self addChild:ball];
//=======Params
// Position and size
b2Vec2 lastPos = b2Vec2(154.0/PTM_RATIO,65.0/PTM_RATIO); //set position first body
float widthBody = 2.0/PTM_RATIO;
float heightBody = 2.0/PTM_RATIO;
// Body params
float density = 0.0;
float restitution = 0.5;
float friction = 0.5;
// Distance joint
float dampingRatio = 0.85;
float frequencyHz = 10;
// Rope joint
float kMaxWidth = 50.0/PTM_RATIO;
// Bodies
int countBodyInChain = 68;
b2Body* prevBody;
//========Create bodies and joints
for (int k = 0; k < countBodyInChain; k++) {
b2BodyDef bodyDef;
if(k==0 || k==countBodyInChain-1) bodyDef.type = b2_staticBody; //first and last bodies are static
else bodyDef.type = b2_dynamicBody;
bodyDef.position = lastPos;
bodyDef.fixedRotation = YES;
b2Body* body = world->CreateBody(&bodyDef);
b2PolygonShape distBodyBox;
distBodyBox.SetAsBox(widthBody, heightBody);
b2FixtureDef fixDef;
fixDef.density = density;
fixDef.restitution = restitution;
fixDef.friction = friction;
fixDef.shape = &distBodyBox;
body->CreateFixture(&fixDef);
if(k>0) {
b2RevoluteJointDef armJointDef;
armJointDef.Initialize(prevBody, body, lastPos);
armJointDef.enableMotor = true;
armJointDef.enableLimit = true;
armJointDef.maxMotorTorque = 1;
world->CreateJoint(&armJointDef);
//Create rope joint
b2RopeJointDef rDef;
rDef.maxLength = (body->GetPosition() - prevBody->GetPosition()).Length() * kMaxWidth;
rDef.localAnchorA = rDef.localAnchorB = b2Vec2_zero;
rDef.bodyA = prevBody;
rDef.bodyB = body;
rDef.collideConnected = false;
world->CreateJoint(&rDef);
} //if k>0
lastPos += b2Vec2(widthBody, 0); //modify b2Vect for next body
prevBody = body;
} //for -loop
[self scheduleUpdate];
}
return self;
}
Problem is that when the app starts, rubber band appears in stretched form in U shape and then it gradually start contracting and coming to become straight horizontally. Can anyone please tell me why it is happening? I want the rubber band to be without being stretched in the beginning.
Best Regards
You don't update lastPos so all bodies occupy the same position initially. Box2D will force them apart and this could lead to the problem.

How can I restrict the scrolling of a UIImageView to the bounds of the UIImage like in iPhoto?

Here is an image in iPhoto:
Here is it zoomed in to the top left corner in iPhoto:
Here is the same image in my app:
Here it is zoomed in to the top left corner in my app:
How can I lose the excess grey space surrounding my image and restrict the scrolling to the bounds of the UIImage like iPhoto?
Thanks
You could use a library that does that. Try MWPhotoBrowser.
So, aside from using a 3rd party library, I solved this problem using:
iOS. How do I restrict UIScrollview scrolling to a limited extent? , adapting the answer to the following methods, which are I hope self explanatory:
- (CGRect) methodThatGetsImageSizeOnScreen
{
float frameHeight;
float frameWidth;
float frameXOrigin;
float frameYOrigin;
float threshold;
BOOL thisImageTouchesLeftAndRight;
UIInterfaceOrientation thisOrientation = self.interfaceOrientation;
if (UIInterfaceOrientationIsLandscape(thisOrientation)){
threshold = 748.0/1024.0;
if ((self.imageToPresent.size.height == self.imageToPresent.size.width) | ((self.imageToPresent.size.height/self.imageToPresent.size.width) > threshold)){
thisImageTouchesLeftAndRight = NO;
frameWidth = (748/self.imageToPresent.size.height)*self.imageToPresent.size.width;
frameHeight = 748;
frameXOrigin = (1024-frameWidth)/2;
frameYOrigin = 0;
}
else
{
thisImageTouchesLeftAndRight = YES;
frameWidth = 1024;
frameHeight = (1024/self.imageToPresent.size.width)*self.imageToPresent.size.height;
frameXOrigin = 0;
frameYOrigin = (748-frameHeight)/2;
}
}
else {
threshold = 768.0/1004.0;
if ((self.imageToPresent.size.height == self.imageToPresent.size.width) | ((self.imageToPresent.size.width/self.imageToPresent.size.height) > threshold)){
thisImageTouchesLeftAndRight = YES;
frameWidth = 768;
frameHeight = (768/self.imageToPresent.size.width)*self.imageToPresent.size.height;
frameXOrigin = 0;
frameYOrigin = (1004-frameHeight)/2;
}
else
{
thisImageTouchesLeftAndRight = NO;
frameWidth = (1004/self.imageToPresent.size.height)*self.imageToPresent.size.width;
frameHeight = 1004;
frameXOrigin = (768-frameWidth)/2;
frameYOrigin = 0;
}
}
CGRect theRect = CGRectMake(frameXOrigin, frameYOrigin, frameWidth, frameHeight);
return theRect;
}
#pragma mark - UIScrollViewDelegate
- (void) scrollViewDidScroll:(UIScrollView*)scroll{
UIInterfaceOrientation thisOrientation = self.interfaceOrientation;
float largeDimension;
float smallDimension;
if (UIInterfaceOrientationIsLandscape(thisOrientation)){
largeDimension = 1024;
smallDimension = 748;
}
else{
largeDimension = 1004;
smallDimension = 768;
}
CGPoint offset = scroll.contentOffset;
CGRect results = [self methodThatGetsImageSizeOnScreen];
float frameHeight = results.size.height;
float frameYOrigin = results.origin.y;
float frameWidth = results.size.width;
float frameXOrigin = results.origin.x;
//So, we start the limiting of a landscape image in portrait (in the y direction) when we exceed the following criteria:
if((frameHeight*self.scrollView.zoomScale) > largeDimension){
if(offset.y < self.scrollView.zoomScale*frameYOrigin) offset.y = self.scrollView.zoomScale*frameYOrigin;
if(offset.y > ((self.scrollView.zoomScale*frameYOrigin)+(frameHeight*self.scrollView.zoomScale)-largeDimension)) offset.y = ((self.scrollView.zoomScale*frameYOrigin)+(frameHeight*self.scrollView.zoomScale)-largeDimension);
}
if((frameWidth*self.scrollView.zoomScale) > largeDimension){
if(offset.x < self.scrollView.zoomScale*frameXOrigin) offset.x = self.scrollView.zoomScale*frameXOrigin;
if(offset.x > ((self.scrollView.zoomScale*frameXOrigin)+(frameWidth*self.scrollView.zoomScale)-largeDimension)) offset.x = ((self.scrollView.zoomScale*frameXOrigin)+(frameWidth*self.scrollView.zoomScale)-largeDimension);
}
// Set offset to adjusted value
scroll.contentOffset = offset;
//Remember you may want your minimum zoomScale set in viewDidLoad or viewWillAppear
}

schedule update issue

This might sound pretty straightforward. I've created a method and I've called it as below in the init method.
[self createNewSpr:ccp(s.width * 0.25,s.height-200)];
[self createNewSpr:ccp(s.width * 0.50,s.height-200)];
[self createNewSpr:ccp(s.width * 0.75,s.height-200)];
[self scheduleUpdate];
I've defined a for loop in my update method that imposes a gravity higher than that of the world on the sprites. Only the last call is affected by the new gravity but the first and second act on the world gravity. I am not sure what is wrong but I suspect it to be the scheduleUpdate. Please Help.
Edit: Update Method :
-(void) update: (ccTime) dt
{
int32 velocityIterations = 8;
int32 positionIterations = 1;
world->Step(dt, velocityIterations, positionIterations);
for (b2Body* b = world->GetBodyList(); b; b = b->GetNext())
{
if (b == sprite)
{
b->ApplyForce( b2Vec2(0.0,20*b->GetMass()),b->GetWorldCenter());
}
}
}
the createNewSpr:
-(void) createNewSpr:(CGPoint)pos {
//CGSize s = [CCDirector sharedDirector].winSize;
b2Vec2 startPos = [self toMeters:pos];
CGFloat linkHeight = 0.24;
CGFloat linkWidth = 0.1;
b2BodyDef bodyDef;
bodyDef.type = b2_dynamicBody;
bodyDef.position = startPos;
b2FixtureDef fixtureDef;
fixtureDef.density = 0.1;
b2PolygonShape polygonShape;
polygonShape.SetAsBox(linkWidth,linkHeight);
fixtureDef.shape = &polygonShape;
//first
b2Body* link = world->CreateBody( &bodyDef );
link->CreateFixture( &fixtureDef );
PhysicsSprite* segmentSprite = [PhysicsSprite spriteWithFile:#"sg.png"];
[self addChild:segmentSprite];
[segmentSprite setPhysicsBody:link];
b2RevoluteJointDef revoluteJointDef;
revoluteJointDef.localAnchorA.Set( 0, linkHeight);
revoluteJointDef.localAnchorB.Set( 0, -linkHeight);
for (int i = 0; i < 10; i++) {
b2Body* newLink = world->CreateBody( &bodyDef );
newLink->CreateFixture( &fixtureDef );
PhysicsSprite* segmentSprite = [PhysicsSprite spriteWithFile:#"sg.png"];
[self addChild:segmentSprite];
[segmentSprite setPhysicsBody:link];
revoluteJointDef.bodyA = link;
revoluteJointDef.bodyB = newLink;
world->CreateJoint( &revoluteJointDef );
link = newLink;//next iteration
}
PhysicsSprite* circleBodySprite = [PhysicsSprite spriteWithFile:#"cb.png"];
[self addChild:circleBodySprite z:1];
b2CircleShape circleShape;
circleShape.m_radius = circleBodySprite.contentSize.width/2 / PTM_RATIO;
fixtureDef.shape = &circleShape;
b2Body* chainBase =world->CreateBody( &bodyDef );
chainBase->CreateFixture( &fixtureDef );
[circleBodySprite setPhysicsBody:chainBase];
sprite = chainBase;
revoluteJointDef.bodyA = link;
revoluteJointDef.bodyB = chainBase;
revoluteJointDef.localAnchorA.Set(0,linkWidth);
revoluteJointDef.localAnchorB.Set(0,linkWidth);
world->CreateJoint( &revoluteJointDef );
}
The problem is with createNewSpr method...
You have assigned sprite to a body... So When you call this method three times, sprite refers to 3rd object only..
When you compare in update method, it just puts gravity on 3rd object...
Hope this helps.. :)

cocos2d and chipmunk rotate object after collision

hi
im pretty new to both frameworks. but maybe someone can point me into the right direction:
basically i try to bounce a ball of a shape. (works fine)
but it would be great when the ball would rotate, too
here is my (copy & paste) code
// BallLayer.m
#import "BallLayer.h"
void updateShape(void* ptr, void* unused){
cpShape* shape = (cpShape*)ptr;
Sprite* sprite = shape->data;
if(sprite){
cpBody* body = shape->body;
[sprite setPosition:cpv(body->p.x, body->p.y)];
}
}
#implementation BallLayer
-(void)tick:(ccTime)dt{
cpSpaceStep(space, 1.0f/60.0f);
cpSpaceHashEach(space->activeShapes, &updateShape, nil);
}
-(void)setupChipmunk{
cpInitChipmunk();
space = cpSpaceNew();
space->gravity = cpv(0,-2000);
space->elasticIterations = 1;
[self schedule: #selector(tick:) interval: 1.0f/60.0f];
cpBody* ballBody = cpBodyNew(200.0, cpMomentForCircle(100.0, 10, 10, cpvzero));
ballBody->p = cpv(150, 400);
cpSpaceAddBody(space, ballBody);
cpShape* ballShape = cpCircleShapeNew(ballBody, 20.0, cpvzero);
ballShape->e = 0.8;
ballShape->u = 0.8;
ballShape->data = ballSprite;
ballShape->collision_type = 1;
cpSpaceAddShape(space, ballShape);
cpBody* floorBody = cpBodyNew(INFINITY, INFINITY);
floorBody->p = cpv(0, 0);
cpShape* floorShape = cpSegmentShapeNew(floorBody, cpv(0,0), cpv(320,160), 0);
floorShape->e = 0.5;
floorShape->u = 0.1;
floorShape->collision_type = 0;
cpSpaceAddStaticShape(space, floorShape);
floorShape = cpSegmentShapeNew(floorBody, cpv(0,200), cpv(320,0), 0);
cpSpaceAddStaticShape(space, floorShape);
}
-(id)init{
self = [super init];
if(nil != self){
ballSprite = [Sprite spriteWithFile:#"ball2.png"];
[ballSprite setPosition:CGPointMake(150, 400)];
[self add:ballSprite];
[self setupChipmunk];
}
return self;
}
#end
please help me out.
well when i decided psoting it i found the solution :)
void updateShape(void* ptr, void* unused)
{
cpShape* shape = (cpShape*)ptr;
Sprite* sprite = shape->data;
if(sprite){
cpBody* body = shape->body;
[sprite setPosition:cpv(body->p.x, body->p.y)];
[sprite setRotation: (float) CC_RADIANS_TO_DEGREES( -body->a )];
}
}