ios - OpenGL 2.0 Bug - Setup and shaders work, won't draw -
i've got uiview loads opengl. setup works fine (you can test 'erase' call different colors) , shaders compiled without error.
the shaders basic: vertex shader takes position, fragment shader renders black.
however, won't draw. i've picked apart problem hours , can't find bug.
please help.
#pragma mark imports #import "ochrdrawingview.h" #pragma mark - definitions #define loquacious yes typedef struct { glfloat x; glfloat y; } vertex; typedef vertex vector; typedef struct { glfloat r; glfloat g; glfloat b; glfloat a; } color; #pragma mark - inline functions static inline glfloat distancebetweenvertices (vertex one, vertex two) { return sqrtf((two.x - one.x) * (two.x - one.x) + (two.y - one.y) * (two.y - one.y)); } static inline glfloat magnitudeofvector (vector vec) { return sqrtf(vec.x * vec.x + vec.y * vec.y); } static inline glfloat dotproductofvectors(vector one, vector two) { return (one.x *two.x + one.y * two.y); } static inline glfloat crossproductofvectors (vector one, vector two) { return (one.x * two.y - one.y * two.x); } static inline vector vectorfromvertices (vertex one, vertex two) { return (vector) { two.x - one.x, two.y - one.y }; } #pragma mark - variables , implementation @implementation ochrdrawingview { eaglcontext *context; caeagllayer *eagllayer; // buffers gluint renderbuffer; gluint framebuffer; gluint vertexbufferid; // attributes in shader program gluint positionattribute; gluint colorattribute; gluint shaderprogram; // pixel dimensions of backbuffer glint backingwidth; glint backingheight; // bools bool isfirsttouch; // points drawing cgpoint origin; cgpoint control; cgpoint destination; } @synthesize currentcolor; #pragma mark - opengl setup + (class) layerclass { return [caeagllayer class]; } - (void) setuplayer { if (loquacious) nslog(@"setuplayer called in ochrdrawingview"); eagllayer = (caeagllayer *) self.layer; [eagllayer setopaque:yes]; [eagllayer setdrawableproperties:[nsdictionary dictionarywithobjectsandkeys:[nsnumber numberwithbool:yes], keagldrawablepropertyretainedbacking, keaglcolorformatrgba8, keagldrawablepropertycolorformat, nil]]; } - (void) setupcontext { if (loquacious) nslog(@"setupcontext called in ochrdrawingview"); context = [[eaglcontext alloc] initwithapi:keaglrenderingapiopengles2]; [eaglcontext setcurrentcontext:context]; if (!context) { nslog(@"context failed set properly"); } } - (void) setuprenderbuffer { if (loquacious) nslog(@"setuprenderbuffer called in ochrdrawingview"); glgenrenderbuffers(1, &renderbuffer); glbindrenderbuffer(gl_renderbuffer, renderbuffer); [context renderbufferstorage:gl_renderbuffer fromdrawable:eagllayer]; } - (void) setupframebuffer { if (loquacious) nslog(@"setupframebuffer called in ochrdrawingview"); glgenframebuffers(1, &framebuffer); glbindframebuffer(gl_framebuffer, framebuffer); glframebufferrenderbuffer(gl_framebuffer, gl_color_attachment0, gl_renderbuffer, renderbuffer); } - (void) setupviewport { if (loquacious) nslog(@"setupviewport called in ochrdrawingview"); glgetrenderbufferparameteriv(gl_renderbuffer, gl_renderbuffer_width, &backingwidth); glgetrenderbufferparameteriv(gl_renderbuffer, gl_renderbuffer_height, &backingheight); glviewport(0, 0, backingwidth, backingheight); } - (void) setupvertexbuffer { glgenbuffers(1, &vertexbufferid); } #pragma mark - shaders - (gluint)compileshaderoftype:(glenum)shadertype { nsstring *shaderstring; nsstring *vertexstring = @" attribute vec4 position; " @" void main (void) { " @" gl_position = position; " @" gl_pointsize = 16.0; " @" } "; nsstring *fragmentstring = @" void main (void) { " @" gl_fragcolor = vec4(0.0, 0.0, 0.0, 1.0); " @" } " ; if (shadertype == gl_vertex_shader) { shaderstring = vertexstring; if (loquacious) nslog(@"about compile vertex shader"); } else if (shadertype == gl_fragment_shader) { shaderstring = fragmentstring; if (loquacious) nslog(@"about compile fragment shader"); } else { nslog(@"not valid shader type"); } gluint shaderhandle = glcreateshader(shadertype); const char *shaderstringutf8 = [shaderstring utf8string]; int shaderstringlength = [shaderstring length]; glshadersource(shaderhandle, 1, &shaderstringutf8, &shaderstringlength); glcompileshader(shaderhandle); glint compilesuccess; glgetshaderiv(shaderhandle, gl_compile_status, &compilesuccess); if (compilesuccess == gl_false) { glchar messages[256]; glgetshaderinfolog(shaderhandle, sizeof(messages), 0, &messages[0]); nsstring *messagestring = [nsstring stringwithutf8string:messages]; nslog(@"%@", messagestring); exit(1); } return shaderhandle; } - (void)compileshaders { if (loquacious) nslog(@"compileshaders called in ochrdrawingview"); gluint vertexshader = [self compileshaderoftype:gl_vertex_shader]; gluint fragmentshader = [self compileshaderoftype:gl_fragment_shader]; shaderprogram = glcreateprogram(); glattachshader(shaderprogram, vertexshader); glattachshader(shaderprogram, fragmentshader); gllinkprogram(shaderprogram); glint linksuccess; glgetprogramiv(shaderprogram, gl_link_status, &linksuccess); if (linksuccess == gl_false) { glchar messages[256]; glgetprograminfolog(shaderprogram, sizeof(messages), 0, &messages[0]); nsstring *messagestring = [nsstring stringwithutf8string:messages]; nslog(@"%@", messagestring); exit(1); } gluseprogram(shaderprogram); positionattribute = glgetattriblocation(shaderprogram, "position"); glenablevertexattribarray(positionattribute); } #pragma mark - init call - (id)initwithframe:(cgrect)frame { self = [super initwithframe:frame]; if (self) { if (loquacious) nslog(@"ochrdrawingview initialize."); [self setuplayer]; [self setupcontext]; [self setcontentscalefactor:[[uiscreen mainscreen] scale]]; [self setuprenderbuffer]; [self setupframebuffer]; [self setupvertexbuffer]; [self compileshaders]; [self erase]; } return self; } // erases screen - (void)erase { if (loquacious) nslog(@"erase called in ochrdrawingview."); [eaglcontext setcurrentcontext:context]; // clear buffer glbindframebuffer(gl_framebuffer, framebuffer); glclearcolor(1.0, 1.0, 1.0, 1.0); glclear(gl_color_buffer_bit); // display buffer glbindrenderbuffer(gl_renderbuffer, renderbuffer); [context presentrenderbuffer:gl_renderbuffer]; } #pragma mark - touch response - (void) touchesbegan:(nsset *)touches withevent:(uievent *)event { origin = [[touches anyobject] locationinview:self]; origin.y = self.bounds.size.height - origin.y; isfirsttouch = yes; } - (void) touchesmoved:(nsset *)touches withevent:(uievent *)event { if (isfirsttouch) { isfirsttouch = no; destination = [[touches anyobject] locationinview:self]; destination.y = self.bounds.size.height - destination.y; } else { origin = destination; destination = [[touches anyobject] locationinview:self]; destination.y = self.bounds.size.height - destination.y; } [self renderlinefrompoint:origin topoint:destination]; } // handles end of touch event when touch tap. - (void) touchesended:(nsset *)touches withevent:(uievent *)event { if (isfirsttouch) { destination = [[touches anyobject] locationinview:self]; destination.y = self.bounds.size.height - destination.y; [self renderlinefrompoint:origin topoint:destination]; } } - (void) touchescancelled:(nsset *)touches withevent:(uievent *)event { } #pragma mark - drawing algorithm // drawings line onscreen based on user touches - (void)renderlinefrompoint:(cgpoint)start topoint:(cgpoint)end { static glfloat *vertexbuffer = null; static nsuinteger vertexmax = 64; nsuinteger vertexcount = 0; nsuinteger count; nsuinteger i; [eaglcontext setcurrentcontext:context]; glbindframebuffer(gl_framebuffer, framebuffer); // convert locations points pixels cgfloat scale = self.contentscalefactor; start.x *= scale; start.y *= scale; end.x *= scale; end.y *= scale; // allocate vertex array buffer if (vertexbuffer == null) vertexbuffer = malloc(vertexmax * 2 * sizeof(glfloat)); // add points buffer there drawing points every x pixels count = max(ceilf(sqrtf((end.x - start.x) * (end.x - start.x) + (end.y - start.y) * (end.y - start.y)) / 3), 1); (i = 0; < count; ++i) { if (vertexcount == vertexmax) { vertexmax = 2 * vertexmax; vertexbuffer = realloc(vertexbuffer, vertexmax * 2 * sizeof(glfloat)); } vertexbuffer[2 * vertexcount + 0] = start.x + (end.x - start.x) * ((glfloat) / (glfloat) count); vertexbuffer[2 * vertexcount + 1] = start.y + (end.y - start.y) * ((glfloat) / (glfloat) count); vertexcount++; } // load data vertex buffer object glbindbuffer(gl_array_buffer, vertexbufferid); glbufferdata(gl_array_buffer, vertexcount * 2 * sizeof(glfloat), vertexbuffer, gl_dynamic_draw); glenablevertexattribarray(positionattribute); glvertexattribpointer(positionattribute, 2, gl_float, gl_false, 0, 0); // draw gluseprogram(shaderprogram); gldrawarrays(gl_points, 0, vertexcount); // display buffer glbindrenderbuffer(gl_renderbuffer, renderbuffer); [context presentrenderbuffer:gl_renderbuffer]; } @end
it seems me points drawn outside viewport. opengl uses normalised device coordinates in range [-1..1] both x , y.
you're taking position of touch in screen space different. e.g. ipad [0..1024] , [0..768]. in order draw points have convert them screen space ndc space:
ndc_x = 2*(touch_x/screen_size_x) - 1; ndc_y = 2*(touch_y/screen_size_y) - 1;
Comments
Post a Comment