static int gear_load_shaders(gear_t* self) { assert(self); LOGD("debug"); // face shaders self->face_program = a3d_shader_make_source(FACE_VSHADER, FACE_FSHADER); if(self->face_program == 0) return 0; self->face_attribute_vertex = glGetAttribLocation(self->face_program, "vertex"); self->face_uniform_color = glGetUniformLocation(self->face_program, "color"); self->face_uniform_mvp = glGetUniformLocation(self->face_program, "mvp"); // outward teeth shaders self->outward_program = a3d_shader_make_source(OUTWARD_VSHADER, OUTWARD_FSHADER); if(self->outward_program == 0) goto fail_outward_program; self->outward_attribute_vertex = glGetAttribLocation(self->outward_program, "vertex"); self->outward_attribute_normal = glGetAttribLocation(self->outward_program, "normal"); self->outward_uniform_color = glGetUniformLocation(self->outward_program, "color"); self->outward_uniform_nm = glGetUniformLocation(self->outward_program, "nm"); self->outward_uniform_mvp = glGetUniformLocation(self->outward_program, "mvp"); // cylinder shaders self->cylinder_program = a3d_shader_make_source(CYLINDER_VSHADER, CYLINDER_FSHADER); if(self->cylinder_program == 0) goto fail_cylinder_program; self->cylinder_attribute_vertex = glGetAttribLocation(self->cylinder_program, "vertex"); self->cylinder_attribute_normal = glGetAttribLocation(self->cylinder_program, "normal"); self->cylinder_uniform_color = glGetUniformLocation(self->cylinder_program, "color"); self->cylinder_uniform_nm = glGetUniformLocation(self->cylinder_program, "nm"); self->cylinder_uniform_mvp = glGetUniformLocation(self->cylinder_program, "mvp"); GLenum e = A3D_GL_GETERROR(); if(e != GL_NO_ERROR) goto fail_error; // success return 1; // failure fail_error: glDeleteProgram(self->cylinder_program); fail_cylinder_program: glDeleteProgram(self->outward_program); fail_outward_program: glDeleteProgram(self->face_program); return 0; }
void lzs_renderer_draw(lzs_renderer_t* self) { assert(self); LOGD("debug"); double t0 = a3d_utime(); // stretch screen to 800x480 glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrthof(0.0f, SCREEN_W, SCREEN_H, 0.0f, 0.0f, 2.0f); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); // draw camera glEnable(GL_TEXTURE_EXTERNAL_OES); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glBindTexture(GL_TEXTURE_EXTERNAL_OES, self->texid); glVertexPointer(3, GL_FLOAT, 0, VERTEX); glTexCoordPointer(2, GL_FLOAT, 0, COORDS); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisable(GL_TEXTURE_EXTERNAL_OES); utime_update("setup", &t0); // capture buffers GLint format = TEXGZ_BGRA; GLint type = GL_UNSIGNED_BYTE; glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES, &format); glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE_OES, &type); if((format == TEXGZ_BGRA) && (type == GL_UNSIGNED_BYTE)) { LOGD("readpixels format=0x%X, type=0x%X", format, type); // TODO - check for texgz errors // process buffers texgz_tex_t* bc = self->buffer_color; texgz_tex_t* bg = self->buffer_gray; texgz_tex_t* bsx = self->buffer_sx; texgz_tex_t* bsy = self->buffer_sy; glReadPixels(self->sphero_x - RADIUS_BALL, (SCREEN_H - self->sphero_y - 1) - RADIUS_BALL, bc->width, bc->height, bc->format, bc->type, (void*) bc->pixels); #ifdef DEBUG_BUFFERS texgz_tex_export(bc, "/sdcard/laser-shark/color.texgz"); #endif utime_update("readpixels", &t0); texgz_tex_computegray(bc, bg); utime_update("computegray", &t0); texgz_tex_computeedges3x3(bg, bsx, bsy); utime_update("computeedges", &t0); // compute peak { int x; int y; int peak_x = 0; int peak_y = 0; float peak = 0.0f; float* gpixels = (float*) bg->pixels; float* xpixels = (float*) bsx->pixels; float* ypixels = (float*) bsy->pixels; for(x = 0; x < bg->width; ++x) { for(y = 0; y < bg->height; ++y) { int idx = bg->width*y + x; // compute magnitude squared float magsq = xpixels[idx]*xpixels[idx] + ypixels[idx]*ypixels[idx]; gpixels[idx] = magsq; if(magsq > peak) { peak_x = x; peak_y = y; peak = magsq; } } } LOGD("peak=%f, peak_x=%i, peak_y=%i", peak, peak_x, peak_y); utime_update("computepeak", &t0); #ifdef DEBUG_BUFFERS texgz_tex_export(bg, "/sdcard/laser-shark/peak.texgz"); #endif // move sphero center to match peak self->sphero_x += (float) peak_x - (float) bg->width / 2.0f; self->sphero_y -= (float) peak_y - (float) bg->height / 2.0f; } } else { LOGE("unsupported format=0x%X, type=0x%X", format, type); } // compute phone X, Y center compute_position(self, SCREEN_CX, SCREEN_CY, &self->phone_X, &self->phone_Y); // compute sphero X, Y compute_position(self, self->sphero_x, self->sphero_y, &self->sphero_X, &self->sphero_Y); utime_update("computeposition", &t0); // compute goal float dx = self->phone_X - self->sphero_X; float dy = self->phone_Y - self->sphero_Y; float a = fix_angle(atan2f(dx, dy) * 180.0f / M_PI); self->sphero_goal = a - self->sphero_heading_offset; // compute speed float dotp = cosf((a - self->sphero_heading) * M_PI / 180.0f); if(dotp > 0.0f) { // linearly interpolate speed based on the turning angle self->sphero_speed = SPEED_MAX*dotp + SPEED_MIN*(1.0f - dotp); } else { // go slow to turn around self->sphero_speed = SPEED_MIN; } // draw camera cross-hair { float x = SCREEN_CX; float y = SCREEN_CY; float r = RADIUS_CROSS; limit_position(r, &x, &y); lzs_renderer_crosshair(y - r, x - r, y + r, x + r, 1.0f, 0.0f, 0.0f); } // draw sphero search box { float r = RADIUS_BALL; limit_position(r, &self->sphero_x, &self->sphero_y); float x = self->sphero_x; float y = self->sphero_y; lzs_renderer_drawbox(y - r, x - r, y + r, x + r, 0.0f, 1.0f, 0.0f, 0); } lzs_renderer_step(self); // draw string a3d_texstring_printf(self->string_sphero, "sphero: head=%i, x=%0.1f, y=%0.1f, spd=%0.2f, goal=%i", (int) fix_angle(self->sphero_heading + self->sphero_heading_offset), self->sphero_X, self->sphero_Y, self->sphero_speed, (int) fix_angle(self->sphero_goal)); a3d_texstring_printf(self->string_phone, "phone: heading=%i, slope=%i, x=%0.1f, y=%0.1f", (int) fix_angle(self->phone_heading), (int) fix_angle(self->phone_slope), self->phone_X, self->phone_Y); a3d_texstring_draw(self->string_sphero, 400.0f, 16.0f, 800, 480); a3d_texstring_draw(self->string_phone, 400.0f, 16.0f + self->string_sphero->size, 800, 480); a3d_texstring_draw(self->string_fps, (float) SCREEN_W - 16.0f, (float) SCREEN_H - 16.0f, SCREEN_W, SCREEN_H); utime_update("draw", &t0); //texgz_tex_t* screen = texgz_tex_new(SCREEN_W, SCREEN_H, SCREEN_W, SCREEN_H, TEXGZ_UNSIGNED_BYTE, TEXGZ_BGRA, NULL); //glReadPixels(0, 0, screen->width, screen->height, screen->format, screen->type, (void*) screen->pixels); //texgz_tex_export(screen, "/sdcard/laser-shark/screen.texgz"); //texgz_tex_delete(&screen); A3D_GL_GETERROR(); }
/*********************************************************** * Generate a gear wheel. * * * * Input: inner_radius - radius of hole at center * * outer_radius - radius at center of teeth * * width - width of gear * * teeth - number of teeth * * tooth_depth - depth of tooth * ***********************************************************/ static int gear_generate(gear_t* self, float inner_radius, float outer_radius, float width, int teeth, float tooth_depth) { assert(self); LOGD("debug"); a3d_glsm_t* glsm = a3d_glsm_new(); if(glsm == NULL) { return 0; } int i; float r0, r1, r2, dz; float a0, a1, a2, a3; float u, v, len; r0 = inner_radius; r1 = outer_radius - tooth_depth / 2.0f; r2 = outer_radius + tooth_depth / 2.0f; dz = 0.5f * width; // TODO - generate texture coordinates for "shinny" // draw front face // GL_TRIANGLE_STRIP a3d_glsm_begin(glsm); for(i = 0; i < teeth; i++) { gear_angle(i, teeth, &a0, &a1, &a2, &a3); a3d_glsm_vertex3f(glsm, r0 * cosf(a0), r0 * sinf(a0), dz); a3d_glsm_vertex3f(glsm, r1 * cosf(a0), r1 * sinf(a0), dz); a3d_glsm_vertex3f(glsm, r0 * cosf(a0), r0 * sinf(a0), dz); a3d_glsm_vertex3f(glsm, r1 * cosf(a3), r1 * sinf(a3), dz); } a3d_glsm_vertex3f(glsm, r0 * cosf(0.0f), r0 * sinf(0.0f), dz); a3d_glsm_vertex3f(glsm, r1 * cosf(0.0f), r1 * sinf(0.0f), dz); a3d_glsm_end(glsm); // buffer front face if(a3d_glsm_status(glsm) != A3D_GLSM_COMPLETE) goto fail; self->front_ec = glsm->ec; glBindBuffer(GL_ARRAY_BUFFER, self->front_vid); glBufferData(GL_ARRAY_BUFFER, 3 * glsm->ec * sizeof(GLfloat), glsm->vb, GL_STATIC_DRAW); // draw front sides of teeth // GL_TRIANGLES a3d_glsm_begin(glsm); for(i = 0; i < teeth; i++) { gear_angle(i, teeth, &a0, &a1, &a2, &a3); a3d_glsm_vertex3f(glsm, r1 * cosf(a0), r1 * sinf(a0), dz); // 0 a3d_glsm_vertex3f(glsm, r2 * cosf(a1), r2 * sinf(a1), dz); // 1 a3d_glsm_vertex3f(glsm, r2 * cosf(a2), r2 * sinf(a2), dz); // 2 a3d_glsm_vertex3f(glsm, r1 * cosf(a0), r1 * sinf(a0), dz); // 0 a3d_glsm_vertex3f(glsm, r2 * cosf(a2), r2 * sinf(a2), dz); // 2 a3d_glsm_vertex3f(glsm, r1 * cosf(a3), r1 * sinf(a3), dz); // 3 } a3d_glsm_end(glsm); // buffer front sides of teeth if(a3d_glsm_status(glsm) != A3D_GLSM_COMPLETE) goto fail; self->front_teeth_ec = glsm->ec; glBindBuffer(GL_ARRAY_BUFFER, self->front_teeth_vid); glBufferData(GL_ARRAY_BUFFER, 3 * glsm->ec * sizeof(GLfloat), glsm->vb, GL_STATIC_DRAW); // draw back face // GL_TRIANGLE_STRIP a3d_glsm_begin(glsm); for(i = 0; i < teeth; i++) { gear_angle(i, teeth, &a0, &a1, &a2, &a3); a3d_glsm_vertex3f(glsm, r1 * cosf(a0), r1 * sinf(a0), -dz); a3d_glsm_vertex3f(glsm, r0 * cosf(a0), r0 * sinf(a0), -dz); a3d_glsm_vertex3f(glsm, r1 * cosf(a3), r1 * sinf(a3), -dz); a3d_glsm_vertex3f(glsm, r0 * cosf(a0), r0 * sinf(a0), -dz); } a3d_glsm_vertex3f(glsm, r1 * cosf(0.0f), r1 * sinf(0.0f), -dz); a3d_glsm_vertex3f(glsm, r0 * cosf(0.0f), r0 * sinf(0.0f), -dz); a3d_glsm_end(glsm); // buffer back face if(a3d_glsm_status(glsm) != A3D_GLSM_COMPLETE) goto fail; self->back_ec = glsm->ec; glBindBuffer(GL_ARRAY_BUFFER, self->back_vid); glBufferData(GL_ARRAY_BUFFER, 3 * glsm->ec * sizeof(GLfloat), glsm->vb, GL_STATIC_DRAW); // draw back sides of teeth // GL_TRIANGLES a3d_glsm_begin(glsm); for(i = 0; i < teeth; i++) { gear_angle(i, teeth, &a0, &a1, &a2, &a3); a3d_glsm_vertex3f(glsm, r1 * cosf(a3), r1 * sinf(a3), -dz); // 0 a3d_glsm_vertex3f(glsm, r2 * cosf(a2), r2 * sinf(a2), -dz); // 1 a3d_glsm_vertex3f(glsm, r2 * cosf(a1), r2 * sinf(a1), -dz); // 2 a3d_glsm_vertex3f(glsm, r1 * cosf(a3), r1 * sinf(a3), -dz); // 0 a3d_glsm_vertex3f(glsm, r2 * cosf(a1), r2 * sinf(a1), -dz); // 2 a3d_glsm_vertex3f(glsm, r1 * cosf(a0), r1 * sinf(a0), -dz); // 3 } a3d_glsm_end(glsm); // buffer back sides of teeth if(a3d_glsm_status(glsm) != A3D_GLSM_COMPLETE) goto fail; self->back_teeth_ec = glsm->ec; glBindBuffer(GL_ARRAY_BUFFER, self->back_teeth_vid); glBufferData(GL_ARRAY_BUFFER, 3 * glsm->ec * sizeof(GLfloat), glsm->vb, GL_STATIC_DRAW); // draw outward faces of teeth // GL_TRIANGLE_STRIP // repeated vertices are necessary to achieve flat shading in ES2 a3d_glsm_begin(glsm); for(i = 0; i < teeth; i++) { gear_angle(i, teeth, &a0, &a1, &a2, &a3); if(i > 0) { a3d_glsm_vertex3f(glsm, r1 * cosf(a0), r1 * sinf(a0), dz); a3d_glsm_vertex3f(glsm, r1 * cosf(a0), r1 * sinf(a0), -dz); } u = r2 * cosf(a1) - r1 * cosf(a0); v = r2 * sinf(a1) - r1 * sinf(a0); len = sqrtf(u * u + v * v); u /= len; v /= len; a3d_glsm_normal3f(glsm, v, -u, 0.0f); a3d_glsm_vertex3f(glsm, r1 * cosf(a0), r1 * sinf(a0), dz); a3d_glsm_vertex3f(glsm, r1 * cosf(a0), r1 * sinf(a0), -dz); a3d_glsm_vertex3f(glsm, r2 * cosf(a1), r2 * sinf(a1), dz); a3d_glsm_vertex3f(glsm, r2 * cosf(a1), r2 * sinf(a1), -dz); a3d_glsm_normal3f(glsm, cosf(a0), sinf(a0), 0.0f); a3d_glsm_vertex3f(glsm, r2 * cosf(a1), r2 * sinf(a1), dz); a3d_glsm_vertex3f(glsm, r2 * cosf(a1), r2 * sinf(a1), -dz); a3d_glsm_vertex3f(glsm, r2 * cosf(a2), r2 * sinf(a2), dz); a3d_glsm_vertex3f(glsm, r2 * cosf(a2), r2 * sinf(a2), -dz); u = r1 * cosf(a3) - r2 * cosf(a2); v = r1 * sinf(a3) - r2 * sinf(a2); a3d_glsm_normal3f(glsm, v, -u, 0.0f); a3d_glsm_vertex3f(glsm, r2 * cosf(a2), r2 * sinf(a2), dz); a3d_glsm_vertex3f(glsm, r2 * cosf(a2), r2 * sinf(a2), -dz); a3d_glsm_vertex3f(glsm, r1 * cosf(a3), r1 * sinf(a3), dz); a3d_glsm_vertex3f(glsm, r1 * cosf(a3), r1 * sinf(a3), -dz); a3d_glsm_normal3f(glsm, cosf(a0), sinf(a0), 0.0f); a3d_glsm_vertex3f(glsm, r1 * cosf(a3), r1 * sinf(a3), dz); a3d_glsm_vertex3f(glsm, r1 * cosf(a3), r1 * sinf(a3), -dz); } a3d_glsm_vertex3f(glsm, r1 * cosf(0.0f), r1 * sinf(0.0f), dz); a3d_glsm_vertex3f(glsm, r1 * cosf(0.0f), r1 * sinf(0.0f), -dz); a3d_glsm_end(glsm); // buffer outward faces of teeth if(a3d_glsm_status(glsm) != A3D_GLSM_COMPLETE) goto fail; self->outward_ec = glsm->ec; glBindBuffer(GL_ARRAY_BUFFER, self->outward_vid); glBufferData(GL_ARRAY_BUFFER, 3 * glsm->ec * sizeof(GLfloat), glsm->vb, GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, self->outward_nid); glBufferData(GL_ARRAY_BUFFER, 3 * glsm->ec * sizeof(GLfloat), glsm->nb, GL_STATIC_DRAW); // draw inside radius cylinder // GL_TRIANGLE_STRIP a3d_glsm_begin(glsm); for(i = 0; i < teeth; i++) { gear_angle(i, teeth, &a0, &a1, &a2, &a3); a3d_glsm_normal3f(glsm, -cosf(a0), -sinf(a0), 0.0f); a3d_glsm_vertex3f(glsm, r0 * cosf(a0), r0 * sinf(a0), -dz); a3d_glsm_vertex3f(glsm, r0 * cosf(a0), r0 * sinf(a0), dz); } a3d_glsm_normal3f(glsm, -cosf(0.0f), -sinf(0.0f), 0.0f); a3d_glsm_vertex3f(glsm, r0 * cosf(0.0f), r0 * sinf(0.0f), -dz); a3d_glsm_vertex3f(glsm, r0 * cosf(0.0f), r0 * sinf(0.0f), dz); a3d_glsm_end(glsm); // buffer inside radius cylinder if(a3d_glsm_status(glsm) != A3D_GLSM_COMPLETE) goto fail; self->cylinder_ec = glsm->ec; glBindBuffer(GL_ARRAY_BUFFER, self->cylinder_vid); glBufferData(GL_ARRAY_BUFFER, 3 * glsm->ec * sizeof(GLfloat), glsm->vb, GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, self->cylinder_nid); glBufferData(GL_ARRAY_BUFFER, 3 * glsm->ec * sizeof(GLfloat), glsm->nb, GL_STATIC_DRAW); GLenum e = A3D_GL_GETERROR(); if(e != GL_NO_ERROR) goto fail; // success glBindBuffer(GL_ARRAY_BUFFER, 0); a3d_glsm_delete(&glsm); return 1; // failure fail: glBindBuffer(GL_ARRAY_BUFFER, 0); a3d_glsm_delete(&glsm); return 0; }