// Returns the vector v that is the image of u under the rotation represented by q xyz_t quaternion_rotate (quaternion_t q, xyz_t u) { quaternion_t u_quat = {0, u.x, u.y, u.z}; quaternion_t v_quat = quaternion_mul(q, quaternion_mul(u_quat, quaternion_inv(q))); xyz_t v = {v_quat.x, v_quat.y, v_quat.z}; return v; }
static void on_mouse_move(struct glwin *win, int x, int y) { struct quaternion next; quaternion_mul(&q_delta, &q_cur, &next); if (g_mouse_down[0]) { float axis[3]; axis[0] = g_dy[0] - y; axis[1] = g_dx[0] - x; axis[2] = 0; float norm = sqrtf((axis[0] * axis[0]) + (axis[1] * axis[1]) + (axis[2] * axis[2])); if (norm > 0) { axis[0] /= norm; axis[1] /= norm; axis[2] /= norm; } quaternion_from_axis_angle(&q_delta, axis[0], axis[1], axis[2], norm * 3 / win->width); g_need_redraw = true; } if (g_mouse_down[2]) { float delta[3]; delta[0] = (g_dx[2] - x) * 2.0 / win->width; delta[1] = -(g_dy[2] - y) * 2.0 / win->height; delta[2] = 0; quaternion_unit_inv_mul_vec3(&next, delta, g_offset_next); g_offset_next[0] = -g_offset_next[0]; g_offset_next[1] = -g_offset_next[1]; g_offset_next[2] = -g_offset_next[2]; g_need_redraw = true; } }
void sea_update() { camera* cam = entity_get("camera"); light* sun = entity_get("sun"); wave_time += frame_time(); static_object* corvette = entity_get("corvette"); corvette->position.y = (sin(wave_time) + 1) / 2; corvette->rotation = quaternion_pitch(sin(wave_time * 1.123) / 50); corvette->rotation = quaternion_mul(corvette->rotation, quaternion_yaw(sin(wave_time * 1.254) / 25)); corvette->rotation = quaternion_mul(corvette->rotation, quaternion_roll(sin(wave_time * 1.355) / 100)); static_object* center_sphere = entity_get("center_sphere"); physics_object* balls[100]; int num_balls; entities_get(balls, &num_balls, physics_object); for(int i = 0; i < num_balls; i++) { physics_object_collide_static(balls[i], center_sphere, frame_time()); physics_object_collide_static(balls[i], corvette, frame_time()); physics_object_update(balls[i], frame_time()); } Uint8 keystate = SDL_GetMouseState(NULL, NULL); if(keystate & SDL_BUTTON(3)){ sun->position.x += (float)mouse_y / 2; sun->position.z -= (float)mouse_x / 2; } mouse_x = 0; mouse_y = 0; ui_button* framerate = ui_elem_get("framerate"); ui_button_set_label(framerate, frame_rate_string()); }
static void on_mouse_button_up(struct glwin *win, int button, int x, int y) { if (g_mouse_down[0] && button == 1) { struct quaternion next; quaternion_mul(&q_delta, &q_cur, &next); q_cur = next; q_delta.x = 0; q_delta.y = 0; q_delta.z = 0; q_delta.w = 1; need_redraw(g_L); } if (g_mouse_down[2] && button == 3) { g_offset[0] += g_offset_next[0]; g_offset[1] += g_offset_next[1]; g_offset[2] += g_offset_next[2]; g_offset_next[0] = 0; g_offset_next[1] = 0; g_offset_next[2] = 0; need_redraw(g_L); } g_mouse_down[button -1] = false; on_mouse_move(win, x, y); }
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; }
// rephrases the attitude quaternion ``absol'' with respect to the attitude // quaternion ``tare'' quaternion_t quaternion_relate (quaternion_t absol, quaternion_t tare) { return quaternion_mul(absol, quaternion_inv(tare)); }