static void redraw(struct glwin *win) { struct glwin_thread_state thread_state; glwin_get_thread_state(&thread_state); glwin_make_current(win, g_ctx); lua_State *L = g_L; static bool gl_init_attempted = false; static bool gl_init_result = false; if (!gl_init_attempted) { gl_init_result = glb_glcore_init(3, 3); } if (!gl_init_result) { printf("Failed to initialize OpenGL bindings\n"); exit(-1); return; } glViewport(0, 0, win->width, win->height); glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable(GL_DEPTH_TEST); lua_getglobal(L, "b2l_data"); //1 if (!lua_istable(L, -1)) { lua_pop(L, 1); goto end; } lua_getfield(L, -1, "objects"); //2 lua_getglobal(L, "current_object"); //3 if (!lua_isstring(L, -1)) { lua_pop(L, 3); goto end; } const char *current_object = lua_tostring(L, -1); lua_getfield(L, -2, current_object); //4 if (lua_isnil(L, -1)) { lua_pop(L, 4); goto end; } lua_getfield(L, -1, "type"); //5 if(strcmp(lua_tostring(L, -1), "MESH")) { lua_pop(L, 5); goto end; } lua_getfield(L, -2, "data"); //6 lua_getfield(L, -6, "meshes"); //7 lua_getfield(L, -1, lua_tostring(L, -2)); //8 if (lua_isnil(L, -1)) { lua_pop(L, 8); goto end; } if (!g_gl_state.initialized) init_gl_state(); if (g_gl_state.recompile_shaders) g_gl_state.program_valid = recompile_shaders(); if (!g_gl_state.initialized || !g_gl_state.program_valid) { lua_pop(L, 8); goto end; } g_gl_state.recompile_shaders = false; glUseProgram(g_gl_state.program); glBindVertexArray(g_gl_state.vao); if (g_gl_state.blob_updated) { glBufferData(GL_ARRAY_BUFFER, g_gl_state.blob_size, g_gl_state.blob ,GL_STATIC_DRAW); g_gl_state.blob_updated = false; } lua_getfield(L, -1, "vertex_normal_array_offset"); //9 int vertex_normal_array_offset = lua_tointeger(L, -1); lua_getfield(L, -2, "uv_array_offset"); //10 int uv_array_offset = lua_tointeger(L, -1); lua_getfield(L, -3, "uv_layers"); //11 lua_len(L, -1); //12 int num_uv_layers = lua_tointeger(L, -1); int tangent_array_offset; if (num_uv_layers > 0) { lua_getfield(L, -5, "tangent_array_offset"); tangent_array_offset = lua_tointeger(L, -1); lua_pop(L, 1); } lua_getfield(L, -5, "vertex_co_array_offset"); //13 int vertex_co_array_offset = lua_tointeger(L, -1); lua_getfield(L, -6, "weights_per_vertex"); //14 int weights_per_vertex = lua_tointeger(L, -1); int weights_array_offset; if (weights_per_vertex > 0) { lua_getfield(L, -7, "weights_array_offset"); weights_array_offset = lua_tointeger(L, -1); lua_pop(L, 1); } else { weights_array_offset = -1; } lua_getfield(L, -11, "vertex_groups"); //15 int num_vertex_groups; if (lua_isnil(L, -1)) { num_vertex_groups = 0; } else { lua_len(L, -1); num_vertex_groups = lua_tointeger(L, -1); lua_pop(L, 1); } glBindVertexBuffer(NORMAL, g_gl_state.vbo, vertex_normal_array_offset, sizeof(float) * 3); if (num_uv_layers > 0) { glBindVertexBuffer(UV, g_gl_state.vbo, uv_array_offset, sizeof(float) * 2 * num_uv_layers); glBindVertexBuffer(TANGENT, g_gl_state.vbo, tangent_array_offset, sizeof(float) * 4); } glBindVertexBuffer(POS, g_gl_state.vbo, vertex_co_array_offset, sizeof(float) * 3); if (weights_per_vertex > 0) glBindVertexBuffer(WEIGHTS, g_gl_state.vbo, weights_array_offset, weights_per_vertex * 4); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_gl_state.vbo); if (g_gl_state.normal_index >= 0) { glEnableVertexAttribArray(g_gl_state.normal_index); glVertexAttribFormat(g_gl_state.normal_index, 3, GL_FLOAT, GL_FALSE, 0); glVertexAttribBinding(g_gl_state.normal_index, NORMAL); } if (g_gl_state.uv_index >= 0) { glEnableVertexAttribArray(g_gl_state.uv_index); glVertexAttribFormat(g_gl_state.uv_index, 2, GL_FLOAT, GL_FALSE, 0); glVertexAttribBinding(g_gl_state.uv_index, UV); } if (g_gl_state.pos_index >= 0) { glEnableVertexAttribArray(g_gl_state.pos_index); glVertexAttribFormat(g_gl_state.pos_index, 3, GL_FLOAT, GL_FALSE, 0); glVertexAttribBinding(g_gl_state.pos_index, POS); } int i = 0; for (i = 0; i < 6; i++) { if (g_gl_state.weights_index[i] >= 0 && weights_per_vertex > 0) { glEnableVertexAttribArray(g_gl_state.weights_index[i]); glVertexAttribIFormat(g_gl_state.weights_index[i], 2, GL_SHORT, 4 * i); glVertexAttribBinding(g_gl_state.weights_index[i], WEIGHTS); } } if (num_uv_layers > 0 && g_gl_state.tangent_index >= 0) { glEnableVertexAttribArray(g_gl_state.tangent_index); glVertexAttribFormat(g_gl_state.tangent_index, 4, GL_FLOAT, GL_FALSE, 0); glVertexAttribBinding(g_gl_state.tangent_index, TANGENT); } struct mat4 view; struct mat4 model; struct quaternion next; quaternion_mul(&q_delta, &q_cur, &next); quaternion_to_mat4(&next, &view); view.v[3][3] = 1; mat4_identity(&model); model.v[3][0] = g_offset[0] + g_offset_next[0]; model.v[3][1] = g_offset[1] + g_offset_next[1]; model.v[3][2] = g_offset[2] + g_offset_next[2]; glUniformMatrix4fv(glGetUniformLocation(g_gl_state.program, "model"), 1, GL_FALSE, (GLfloat *)&model); struct mat4 ident; mat4_identity(&ident); glUniformMatrix4fv(glGetUniformLocation(g_gl_state.program, "view"), 1, GL_FALSE, (GLfloat *)&view); float zoom = exp(g_log_zoom); float zr = 100; struct mat4 proj; mat4_zero(&proj); proj.v[0][0] = 1.0/zoom; proj.v[1][1] = 1.0*win->width/(zoom*win->height); proj.v[2][2] = 1.0/zr; proj.v[3][3] = 1.0; glUniformMatrix4fv(glGetUniformLocation(g_gl_state.program, "proj"), 1, GL_FALSE, (GLfloat *)&proj); if (weights_per_vertex > 0) { static int render_count = 0; render_count++; double frame; int frame_start; int frame_end; lua_getglobal(L, "frame_start"); //16 frame_start = lua_tointeger(L, -1); lua_getglobal(L, "frame_end"); //17 frame_end = lua_tointeger(L, -1); lua_getglobal(L, "frame_delta"); //18 frame = frame_start + lua_tonumber(L, -1); int frame_i = floorf(frame); double frame_fract = frame - frame_i; lua_getfield(L, -18, "scenes"); //19 lua_getglobal(L, "current_scene"); //20 lua_getfield(L, -2, lua_tostring(L, -1)); //21 if (!lua_istable(L, -1)) { lua_pop(L, 20); goto end; } lua_getfield(L, -1, "objects"); lua_getfield(L, -1, current_object); lua_getfield(L, -1, "vertex_group_transform_array_offset"); int offset = lua_tointeger(L, -1); lua_pop(L, 9); int stride = sizeof(float) * 4 * 4 * num_vertex_groups; int i; for (i = 0; i < num_vertex_groups; i++) { struct mat4 res; struct mat4 M1; struct mat4 M2; struct mat4 *base = (struct mat4 *)(g_gl_state.blob + offset + (i * sizeof(float) * 4 * 4) + frame_i * stride); struct mat4 *next = (struct mat4 *)(g_gl_state.blob + offset + (i * sizeof(float) * 4 * 4) + (frame_i + 1) * stride); if (frame_i == (frame_end-1)) { next = (struct mat4 *)(g_gl_state.blob + offset + i * sizeof(float) * 4 * 4 + (frame_start) * stride); } else if (frame_fract == 0) { next = base; } #if USE_SLERP struct mat4 temp; mat4_zero(&temp); temp.v[3][3] = 1; M1 = *base; M2 = *next; spherical_lerp(M1.v[0], M2.v[0], frame_fract, temp.v[0]); spherical_lerp(M1.v[1], M2.v[1], frame_fract, temp.v[1]); spherical_lerp(M1.v[2], M2.v[2], frame_fract, temp.v[2]); mat4_transpose(&temp, &res); float v1[3]; float v2[3]; v1[0] = M1.v[0][3]; v1[1] = M1.v[1][3]; v1[2] = M1.v[2][3]; v2[0] = M2.v[0][3]; v2[1] = M2.v[1][3]; v2[2] = M2.v[2][3]; lerp(v1, v2, frame_fract, res.v[3]); #else mat4_zero(&res); res.v[3][3] = 1; mat4_transpose(base, &M1); mat4_transpose(next, &M2); lerp(M1.v[0], M2.v[0], frame_fract, res.v[0]); lerp(M1.v[1], M2.v[1], frame_fract, res.v[1]); lerp(M1.v[2], M2.v[2], frame_fract, res.v[2]); lerp(M1.v[3], M2.v[3], frame_fract, res.v[3]); #endif glUniformMatrix4fv(g_gl_state.groups_index + i, 1, /*num_vertex_groups, */ GL_FALSE, (GLfloat *)&res); } } lua_getglobal(L, "controls"); //16 int controls = lua_gettop(L); lua_getglobal(L, "materials"); //17 int materials = lua_gettop(L); lua_getfield(L, -10, "index_array_offset"); //18 int index_array_offset = lua_tointeger(L, -1); lua_getfield(L, -11, "submeshes"); //19 lua_len(L, -1); //20 int num_submeshes = lua_tointeger(L, -1); for (i = 0; i < num_submeshes; i++) { lua_rawgeti(L, -2, i + 1); lua_getfield(L, -1, "material_name"); const char *material_name = lua_tostring(L, -1); lua_getfield(L, -2, "triangle_no"); int triangle_no = lua_tointeger(L, -1); lua_getfield(L, -3, "triangle_count"); int triangle_count = lua_tointeger(L, -1); lua_getfield(L, materials, material_name); lua_getfield(L, -1, "params"); lua_pushnil(L); /* first key */ while (lua_next(L, -2)) { int variable = lua_gettop(L); const char *variable_name = lua_tostring(L, variable - 1); int uniform_loc = glGetUniformLocation(g_gl_state.program, variable_name); if (uniform_loc == -1) { lua_pop(L, 1); continue; } lua_getfield(L, variable, "value"); int value = variable + 1; lua_getfield(L, variable, "datatype"); const char *datatype = strdup(lua_tostring(L, -1)); lua_pop(L, 1); if (!strcmp(datatype, "bool")) { int bool_value = lua_toboolean(L, value); glUniform1i(uniform_loc, bool_value); } else if (!strcmp(datatype, "vec3")) { lua_rawgeti(L, value, 1); lua_rawgeti(L, value, 2); lua_rawgeti(L, value, 3); float val[3]; val[0] = (float)lua_tonumber(L, -3); val[1] = (float)lua_tonumber(L, -2); val[2] = (float)lua_tonumber(L, -1); glUniform3fv(uniform_loc, 1, val); lua_pop(L, 3); } else if (!strcmp(datatype, "float")) { float fval = lua_tonumber(L, value); glUniform1f(uniform_loc, fval); } else if (!strcmp(datatype, "sampler2D")) { lua_getfield(L, controls, variable_name); int control = lua_gettop(L); lua_getfield(L, control, "needs_upload"); int needs_upload = lua_toboolean(L, -1); lua_pop(L, 1); if (needs_upload) { int texunit; GdkPixbuf *pbuf; lua_getfield(L, control, "texunit"); texunit = lua_tointeger(L, -1) - 1; lua_pop(L, 1); lua_getfield(L, control, "pbuf"); lua_getfield(L, -1, "_native"); pbuf = (GdkPixbuf *)lua_touserdata(L, -1); lua_pop(L, 2); glActiveTexture(GL_TEXTURE0 + texunit); glBindTexture(GL_TEXTURE_2D, g_texture_names[texunit]); int width = gdk_pixbuf_get_width(pbuf); int height = gdk_pixbuf_get_height(pbuf); int n_chan = gdk_pixbuf_get_n_channels(pbuf); glPixelStorei(GL_UNPACK_ROW_LENGTH, gdk_pixbuf_get_rowstride(pbuf)/ n_chan); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glTexImage2D(GL_TEXTURE_2D, 0, /* level */ n_chan > 3 ? GL_RGBA : GL_RGB, width, height, 0, /* border */ n_chan > 3 ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, gdk_pixbuf_get_pixels(pbuf)); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glGenerateMipmap(GL_TEXTURE_2D); glUniform1i(uniform_loc, texunit); lua_pushboolean(L, 0); lua_setfield(L, control, "needs_upload"); } lua_pop(L, 1); } free((void *)datatype); lua_pop(L, 2); } //while (lua_next(L, -2) != 0) glDrawElements(GL_TRIANGLES, 3 * triangle_count, GL_UNSIGNED_SHORT, (void *)((int64_t)index_array_offset) + 3 * 2 * triangle_no); lua_pop(L, 6); } lua_pop(L, 20); end: { GLenum err = glGetError(); if (err) printf("render_scene GL error = %d\n", err); } glwin_swap_buffers(g_win); glwin_set_thread_state(&thread_state); g_need_redraw = false; return; }
int main(int argc, char **argv) { if (argc < 2) { printf("%s: Invalid parms\n", argv[0]); printf("usage: \n"); printf(" %s Tracker0@host\n", argv[0]); return -1; } char *server = argv[1]; pos *phan_position = new pos; pos *phan_offset = new pos; force *phan_force = new force; state *atom_state = new state; int ff_enabled, ff_active; double kspr = 500.0; // Units??? vrpn_Tracker_Remote *tkr; vrpn_Button_Remote *btn; vrpn_ForceDevice_Remote *fdv; printf("Opening: %s ...\n", server); tkr = new vrpn_Tracker_Remote(server); tkr->register_change_handler(phan_position, handle_tracker); btn = new vrpn_Button_Remote(server); btn->register_change_handler(&ff_enabled, handle_button); fdv = new vrpn_ForceDevice_Remote(server); fdv->register_force_change_handler(phan_force, handle_force); void * myglwin = glwin_create(700, 700); if (myglwin == NULL) { printf("Failed to open OpenGL window!!\n"); return -1; } atom_state->x = 0.0; atom_state->y = 0.0; atom_state->z = 0.0; atom_state->vx = 0.0; atom_state->vy = 0.0; atom_state->vz = 0.0; atom_state->ax = 0.0; atom_state->ay = 0.0; atom_state->az = 0.0; atom_state->mass = .001; ff_active = 0; init_graphics(myglwin); GLUquadricObj *qobj = gluNewQuadric(); GLUquadricObj *qatom = gluNewQuadric(); /* * main interactive loop */ while (1) { // Let the tracker do its thing tkr->mainloop(); btn->mainloop(); fdv->mainloop(); run_dynamics(atom_state, phan_force); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); if (ff_enabled ) { if (!ff_active) { // Set up force field so initially the force is zero phan_offset->x = phan_position->x - .2*atom_state->x; phan_offset->y = phan_position->y - .2*atom_state->y; phan_offset->z = phan_position->z - .2*atom_state->z; } // Now turn the force field on // scene -> haptic: rotate 180 about the y axis fdv->setConstraintMode(vrpn_ForceDevice::POINT_CONSTRAINT); float cpos[3]; cpos[0] = -(.2*atom_state->x + phan_offset->x); cpos[1] = (.2*atom_state->y + phan_offset->y); cpos[2] = -(.2*atom_state->z + phan_offset->z); fdv->setConstraintPoint(cpos); fdv->setConstraintKSpring(kspr); fdv->enableConstraint(1); // enable force field ff_active = 1; } else if (ff_active) { fdv->enableConstraint(0); // disable force field ff_active = 0; } draw_axes(); draw_tracker_and_atom(phan_force, qobj, atom_state, qatom); glwin_swap_buffers(myglwin); } } /* main */