static void crop_filter_tick(void *data, float seconds) { struct crop_filter_data *filter = data; vec2_zero(&filter->mul_val); vec2_zero(&filter->add_val); calc_crop_dimensions(filter, &filter->mul_val, &filter->add_val); UNUSED_PARAMETER(seconds); }
static void reset_game() { /* Set the starting level to demo.level */ current_level = asset_get(P("./levels/demo.level")); level_score = 0; level_time = 0.0; /* New main character entity */ character* main_char = entity_get("main_char"); main_char->position = vec2_mul( vec2_new(20, 20), TILE_SIZE); main_char->velocity = vec2_zero(); /* We can create multiple entities using a name format string like printf */ entities_new("coin_id_%i", COIN_COUNT, coin); /* Get an array of pointers to all coin entities */ coin* coins[COIN_COUNT]; entities_get(coins, NULL, coin); /* Set all the coin initial positions */ for(int i = 0; i < COIN_COUNT; i++) { coins[i]->position = vec2_mul(coin_positions[i], TILE_SIZE); } /* Deactivate victory and new game UI elements */ ui_button* victory = ui_elem_get("victory"); ui_button* new_game = ui_elem_get("new_game"); victory->active = false; new_game->active = false; }
static void crop_filter_render(void *data, gs_effect_t *effect) { struct crop_filter_data *filter = data; struct vec2 mul_val; struct vec2 add_val; vec2_zero(&mul_val); vec2_zero(&add_val); calc_crop_dimensions(filter, &mul_val, &add_val); obs_source_process_filter_begin(filter->context, GS_RGBA, OBS_NO_DIRECT_RENDERING); gs_effect_set_vec2(filter->param_mul, &mul_val); gs_effect_set_vec2(filter->param_add, &add_val); obs_source_process_filter_end(filter->context, filter->effect, filter->width, filter->height); UNUSED_PARAMETER(effect); }
static inline vec2 GetOBSScreenSize() { obs_video_info ovi; vec2 size; vec2_zero(&size); if (obs_get_video_info(&ovi)) { size.x = float(ovi.base_width); size.y = float(ovi.base_height); } return size; }
static bool line_line_intersection(vec2 a0, vec2 a1, vec2 b0, vec2 b1) { #if 1 // Implemented based on http://stackoverflow.com/a/17198094/4354008 vec2 v = vec2_sub(a0, a1); vec2 normal = vec2_new(v.y, -v.x); vec2 v0 = vec2_sub(b0, a0); vec2 v1 = vec2_sub(b1, a0); float proj0 = vec2_dot(v0, normal); float proj1 = vec2_dot(v1, normal); if ((proj0 == 0) || (proj1 == 0)) return true; // TODO: float_sign() if ((proj0 > 0) && (proj1 < 0)) return true; if ((proj0 < 0) && (proj1 > 0)) return true; return false; #else vec2 intersection = vec2_zero(); vec2 b = vec2_sub(a1, a0); vec2 d = vec2_sub(b1, b0); float b_dot_p_perp = (b.x * d.y) - (b.y * d.x); if (b_dot_p_perp == 0) return false; vec2 c = vec2_sub(b0, a0); float t = ((c.x * d.y) - (c.y * d.x)) / b_dot_p_perp; if ((t < 0) || (t > 1)) return false; float u = ((c.x * b.y) - (c.y * b.x)) / b_dot_p_perp; if ((u < 0) || (u > 1)) return false; // TODO: make this an output parameter intersection = vec2_add(a0, vec2_mul(b, t)); return true; #endif }
static void add_generator(int type, const struct event *ev) { struct foe_generator *p = get_foe_generator(); if (p != NULL) { p->generator_type = type; p->foe_count = ev->foe_count; p->foe_type = ev->foe_type; if (ev->center) p->center = *ev->center; else vec2_zero(&p->center); p->radius = ev->radius; p->border = ev->wall; p->powerup_type = ev->powerup_type; } }
void OBSBasicPreview::mousePressEvent(QMouseEvent *event) { OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow()); float x = float(event->x()) - main->previewX; float y = float(event->y()) - main->previewY; if (event->button() != Qt::LeftButton) return; mouseDown = true; vec2_set(&startPos, x, y); GetStretchHandleData(startPos); vec2_divf(&startPos, &startPos, main->previewScale); startPos.x = std::round(startPos.x); startPos.y = std::round(startPos.y); mouseOverItems = SelectedAtPos(startPos); vec2_zero(&lastMoveOffset); }
static void jarhead_create(struct foe_jarhead *f) { f->state = JARHEAD_ALIVE; vec2_zero(&f->common.dir); }
coin* coin_new() { coin* c = malloc(sizeof(coin)); c->position = vec2_zero(); return c; }
static void update_item_transform(struct obs_scene_item *item) { uint32_t width = obs_source_get_width(item->source); uint32_t height = obs_source_get_height(item->source); uint32_t cx = calc_cx(item, width); uint32_t cy = calc_cy(item, height); struct vec2 base_origin; struct vec2 origin; struct vec2 scale = item->scale; struct calldata params; uint8_t stack[128]; if (os_atomic_load_long(&item->defer_update) > 0) return; width = cx; height = cy; vec2_zero(&base_origin); vec2_zero(&origin); /* ----------------------- */ if (item->bounds_type != OBS_BOUNDS_NONE) { calculate_bounds_data(item, &origin, &scale, &cx, &cy); } else { cx = (uint32_t)((float)cx * scale.x); cy = (uint32_t)((float)cy * scale.y); } add_alignment(&origin, item->align, (int)cx, (int)cy); matrix4_identity(&item->draw_transform); matrix4_scale3f(&item->draw_transform, &item->draw_transform, scale.x, scale.y, 1.0f); matrix4_translate3f(&item->draw_transform, &item->draw_transform, -origin.x, -origin.y, 0.0f); matrix4_rotate_aa4f(&item->draw_transform, &item->draw_transform, 0.0f, 0.0f, 1.0f, RAD(item->rot)); matrix4_translate3f(&item->draw_transform, &item->draw_transform, item->pos.x, item->pos.y, 0.0f); item->output_scale = scale; /* ----------------------- */ if (item->bounds_type != OBS_BOUNDS_NONE) { vec2_copy(&scale, &item->bounds); } else { scale.x = (float)width * item->scale.x; scale.y = (float)height * item->scale.y; } add_alignment(&base_origin, item->align, (int)scale.x, (int)scale.y); matrix4_identity(&item->box_transform); matrix4_scale3f(&item->box_transform, &item->box_transform, scale.x, scale.y, 1.0f); matrix4_translate3f(&item->box_transform, &item->box_transform, -base_origin.x, -base_origin.y, 0.0f); matrix4_rotate_aa4f(&item->box_transform, &item->box_transform, 0.0f, 0.0f, 1.0f, RAD(item->rot)); matrix4_translate3f(&item->box_transform, &item->box_transform, item->pos.x, item->pos.y, 0.0f); /* ----------------------- */ item->last_width = width; item->last_height = height; calldata_init_fixed(¶ms, stack, sizeof(stack)); calldata_set_ptr(¶ms, "scene", item->parent); calldata_set_ptr(¶ms, "item", item); signal_handler_signal(item->parent->source->context.signals, "item_transform", ¶ms); }
static void recalculate_transition_matrix(obs_source_t *tr, size_t idx) { obs_source_t *child; struct matrix4 mat; struct vec2 pos; struct vec2 scale; float tr_cx = (float)tr->transition_actual_cx; float tr_cy = (float)tr->transition_actual_cy; float source_cx; float source_cy; float tr_aspect = tr_cx / tr_cy; float source_aspect; enum obs_transition_scale_type scale_type = tr->transition_scale_type; lock_transition(tr); child = tr->transition_sources[idx]; if (!child) { unlock_transition(tr); return; } source_cx = (float)obs_source_get_width(child); source_cy = (float)obs_source_get_height(child); unlock_transition(tr); if (source_cx == 0.0f || source_cy == 0.0f) return; source_aspect = source_cx / source_cy; if (scale_type == OBS_TRANSITION_SCALE_MAX_ONLY) { if (source_cx > tr_cx || source_cy > tr_cy) { scale_type = OBS_TRANSITION_SCALE_ASPECT; } else { scale.x = 1.0f; scale.y = 1.0f; } } if (scale_type == OBS_TRANSITION_SCALE_ASPECT) { bool use_width = tr_aspect < source_aspect; scale.x = scale.y = use_width ? tr_cx / source_cx : tr_cy / source_cy; } else if (scale_type == OBS_TRANSITION_SCALE_STRETCH) { scale.x = tr_cx / source_cx; scale.y = tr_cy / source_cy; } source_cx *= scale.x; source_cy *= scale.y; vec2_zero(&pos); add_alignment(&pos, tr->transition_alignment, (int)(tr_cx - source_cx), (int)(tr_cy - source_cy)); matrix4_identity(&mat); matrix4_scale3f(&mat, &mat, scale.x, scale.y, 1.0f); matrix4_translate3f(&mat, &mat, pos.x, pos.y, 0.0f); matrix4_copy(&tr->transition_matrices[idx], &mat); }
void tick_game(struct GameMemory *memory, struct Input *input, uint32 screen_width, uint32 screen_height, float dt) { struct GameState *game_state = (struct GameState *)memory->game_memory; struct RenderBuffer *render_buffer = (struct RenderBuffer *)memory->render_memory; clear_render_buffer(render_buffer); for (uint32 i = 0; i < game_state->visibility_graph.vertex_count; ++i) { vec2 vertex = game_state->visibility_graph.vertices[i]; draw_world_quad_buffered(render_buffer, vertex, vec2_scalar(0.1f), vec4_zero(), vec3_new(0, 1, 1)); } for (uint32 i = 0; i < game_state->visibility_graph.edge_count; ++i) { uint32 *edge = &game_state->visibility_graph.edges[i][0]; vec2 p0 = game_state->visibility_graph.vertices[edge[0]]; vec2 p1 = game_state->visibility_graph.vertices[edge[1]]; draw_world_line_buffered(render_buffer, p0, p1, vec3_new(1, 1, 0)); } if (mouse_down(MOUSE_LEFT, input)) { struct AABB box = calc_mouse_selection_box(input, MOUSE_LEFT); vec2 size = vec2_sub(box.max, box.min); vec2 bottom_left = vec2_new(box.min.x, box.max.y); vec2 bottom_right = vec2_new(box.max.x, box.max.y); vec2 top_left = vec2_new(box.min.x, box.min.y); vec2 top_right = vec2_new(box.max.x, box.min.y); const uint32 outline_thickness = 1; draw_screen_quad_buffered(render_buffer, top_left, vec2_new(size.x, outline_thickness), vec4_zero(), vec3_new(1, 1, 0)); draw_screen_quad_buffered(render_buffer, bottom_left, vec2_new(size.x, outline_thickness), vec4_zero(), vec3_new(1, 1, 0)); draw_screen_quad_buffered(render_buffer, top_left, vec2_new(outline_thickness, size.y), vec4_zero(), vec3_new(1, 1, 0)); draw_screen_quad_buffered(render_buffer, top_right, vec2_new(outline_thickness, size.y), vec4_zero(), vec3_new(1, 1, 0)); } if (mouse_released(MOUSE_LEFT, input)) { // Clear previous selection. game_state->selected_ship_count = 0; struct AABB screen_selection_box = calc_mouse_selection_box(input, MOUSE_LEFT); // Because screen space y-values are inverted, these two results have conflicting // y-values, i.e. screen_to_world_min.y is actually the maximum y. These values // are then properly min/maxed and stored correctly in world_selection_box. vec2 screen_to_world_min = screen_to_world_coords(screen_selection_box.min, &game_state->camera, screen_width, screen_height); vec2 screen_to_world_max = screen_to_world_coords(screen_selection_box.max, &game_state->camera, screen_width, screen_height); struct AABB world_selection_box; world_selection_box.min = min_vec2(screen_to_world_min, screen_to_world_max); world_selection_box.max = max_vec2(screen_to_world_min, screen_to_world_max); // Add colliding ships to the selection list. // TODO: optimize, spatial grid hash? for (uint32 i = 0; i < game_state->ship_count; ++i) { struct Ship *ship = &game_state->ships[i]; struct AABB ship_aabb = aabb_from_transform(ship->position, ship->size); vec2 center = vec2_div(vec2_add(ship_aabb.min, ship_aabb.max), 2.0f); if (aabb_aabb_intersection(world_selection_box, ship_aabb)) game_state->selected_ships[game_state->selected_ship_count++] = ship->id; } if (game_state->selected_ship_count > 0) fprintf(stderr, "selected %u ships\n", game_state->selected_ship_count); } if (mouse_down(MOUSE_RIGHT, input)) { vec2 target_position = screen_to_world_coords(input->mouse_position, &game_state->camera, screen_width, screen_height); for (uint32 i = 0; i < game_state->selected_ship_count; ++i) { uint32 id = game_state->selected_ships[i]; struct Ship *ship = get_ship_by_id(game_state, id); ship->target_position = target_position; ship->move_order = true; } } // Outline selected ships. for (uint32 i = 0; i < game_state->selected_ship_count; ++i) { uint32 id = game_state->selected_ships[i]; struct Ship *ship = get_ship_by_id(game_state, id); draw_world_quad_buffered(render_buffer, ship->position, vec2_mul(ship->size, 1.1f), vec4_zero(), vec3_new(0, 1, 0)); if (ship->move_order) draw_world_quad_buffered(render_buffer, ship->target_position, vec2_new(0.5f, 0.5f), vec4_zero(), vec3_new(0, 1, 0)); } // Handle move orders. for (uint32 i = 0; i < game_state->ship_count; ++i) { struct Ship *ship = &game_state->ships[i]; if (ship->move_order) { vec2 direction = vec2_zero(); /* if (vec2_length2(direction) < FLOAT_EPSILON) direction = vec2_normalize(vec2_sub(ship->target_position, ship->position)); */ ship->move_velocity = vec2_mul(direction, 2.0f); /* vec2 direction = vec2_normalize(vec2_sub(ship->target_position, ship->position)); ship->move_velocity = vec2_mul(direction, 2.0f); */ if (vec2_distance2(ship->position, ship->target_position) < 0.1f) { ship->move_velocity = vec2_zero(); ship->move_order = false; } } } tick_camera(input, &game_state->camera, dt); tick_combat(game_state, dt); tick_physics(game_state, dt); }
static void tick_physics(struct GameState *game_state, float dt) { // Projectile kinematics. for (uint32 i = 0; i < game_state->projectile_count; ++i) { struct Projectile *projectile = &game_state->projectiles[i]; // r = r0 + (v*t) + (a*t^2)/2 projectile->position = vec2_add(projectile->position, vec2_mul(projectile->velocity, dt)); } // Ship kinematics. for (uint32 i = 0; i < game_state->ship_count; ++i) { struct Ship *ship = &game_state->ships[i]; vec2 move_acceleration = vec2_zero(); // v = v0 + (a*t) ship->move_velocity = vec2_add(ship->move_velocity, vec2_mul(move_acceleration, dt)); // r = r0 + (v*t) + (a*t^2)/2 ship->position = vec2_add(vec2_add(ship->position, vec2_mul(ship->move_velocity, dt)), vec2_div(vec2_mul(move_acceleration, dt * dt), 2.0f)); } // // TODO: spatial hashing // // Projectile collision. for (uint32 i = 0; i < game_state->projectile_count; ++i) { struct Projectile *projectile = &game_state->projectiles[i]; struct AABB projectile_aabb = aabb_from_transform(projectile->position, projectile->size); // Projectile-building collision. for (uint32 j = 0; j < game_state->building_count; ++j) { struct Building *building = &game_state->buildings[j]; struct AABB building_aabb = aabb_from_transform(building->position, building->size); if (aabb_aabb_intersection(projectile_aabb, building_aabb)) { // TODO: damage building if not friendly destroy_projectile(game_state, projectile); break; } } // NOTE: owner may be dead and destroyed at this point, so checking for NULL might be required. struct Ship *owner = get_ship_by_id(game_state, projectile->owner); // Projectile-ship collision. for (uint32 j = 0; j < game_state->ship_count; ++j) { struct Ship *ship = &game_state->ships[j]; if (ship->id == projectile->owner) continue; #if 0 // Allow projectiles to pass through teammates. if (ship->team == projectile->team) continue; #endif struct AABB ship_aabb = aabb_from_transform(ship->position, ship->size); if (aabb_aabb_intersection(projectile_aabb, ship_aabb)) { // Disable friendly fire. if (ship->team != projectile->team) damage_ship(game_state, ship, projectile->damage); destroy_projectile(game_state, projectile); break; } } } // TODO: optimize // Ship collision. if (game_state->ship_count >= 2) { for (uint32 i = 0; i < game_state->ship_count - 1; ++i) { struct Ship *a = &game_state->ships[i]; struct AABB a_aabb = aabb_from_transform(a->position, a->size); vec2 a_center = vec2_div(vec2_add(a_aabb.min, a_aabb.max), 2.0f); vec2 a_half_extents = vec2_div(vec2_sub(a_aabb.max, a_aabb.min), 2.0f); // Ship-building collision. for (uint32 j = 0; j < game_state->building_count; ++j) { struct Building *building = &game_state->buildings[j]; struct AABB b_aabb = aabb_from_transform(building->position, building->size); if (aabb_aabb_intersection(a_aabb, b_aabb)) { vec2 b_center = vec2_div(vec2_add(b_aabb.min, b_aabb.max), 2.0f); vec2 b_half_extents = vec2_div(vec2_sub(b_aabb.max, b_aabb.min), 2.0f); vec2 intersection = vec2_sub(vec2_abs(vec2_sub(b_center, a_center)), vec2_add(a_half_extents, b_half_extents)); if (intersection.x > intersection.y) { a->move_velocity.x = 0.0f; if (a->position.x < building->position.x) a->position.x += intersection.x/2.0f; else a->position.x -= intersection.x/2.0f; } else { a->move_velocity.y = 0.0f; if (a->position.y < building->position.y) a->position.y += intersection.y/2.0f; else a->position.y -= intersection.y/2.0f; } } } // Ship-ship collision. for (uint32 j = i + 1; j < game_state->ship_count; ++j) { struct Ship *b = &game_state->ships[j]; struct AABB b_aabb = aabb_from_transform(b->position, b->size); if (aabb_aabb_intersection(a_aabb, b_aabb)) { vec2 b_center = vec2_div(vec2_add(b_aabb.min, b_aabb.max), 2.0f); vec2 b_half_extents = vec2_div(vec2_sub(b_aabb.max, b_aabb.min), 2.0f); vec2 intersection = vec2_sub(vec2_abs(vec2_sub(b_center, a_center)), vec2_add(a_half_extents, b_half_extents)); if (intersection.x > intersection.y) { if (abs_float(a->move_velocity.x) > abs_float(b->move_velocity.x)) a->move_velocity.x = 0.0f; else b->move_velocity.x = 0.0f; if (a->position.x < b->position.x) { a->position.x += intersection.x/2.0f; b->position.x -= intersection.x/2.0f; } else { a->position.x -= intersection.x/2.0f; b->position.x += intersection.x/2.0f; } } else { if (abs_float(a->move_velocity.y) > abs_float(b->move_velocity.y)) a->move_velocity.y = 0.0f; else b->move_velocity.y = 0.0f; if (a->position.y < b->position.y) { a->position.y += intersection.y/2.0f; b->position.y -= intersection.y/2.0f; } else { a->position.y -= intersection.y/2.0f; b->position.y += intersection.y/2.0f; } } } } } } }
static void tick_camera(struct Input *input, struct Camera *camera, float dt) { // // move // vec2 camera_up = vec2_direction(camera->rotation); vec2 camera_right = vec2_direction(camera->rotation - PI_OVER_TWO); vec2 move_acceleration = vec2_zero(); if (key_down(GLFW_KEY_W, input)) move_acceleration = vec2_add(move_acceleration, camera_up); if (key_down(GLFW_KEY_A, input)) move_acceleration = vec2_add(move_acceleration, vec2_negate(camera_right)); if (key_down(GLFW_KEY_S, input)) move_acceleration = vec2_add(move_acceleration, vec2_negate(camera_up)); if (key_down(GLFW_KEY_D, input)) move_acceleration = vec2_add(move_acceleration, camera_right); if (vec2_length2(move_acceleration) > FLOAT_EPSILON) { const float acceleration_magnitude = camera->zoom * 10.0f; move_acceleration = vec2_normalize(move_acceleration); move_acceleration = vec2_mul(move_acceleration, acceleration_magnitude); // v = v0 + (a*t) camera->move_velocity = vec2_add(camera->move_velocity, vec2_mul(move_acceleration, dt)); // Clamp move velocity. const float max_move_speed = 5.0f * sqrtf(camera->zoom); if (vec2_length2(camera->move_velocity) > (max_move_speed * max_move_speed)) camera->move_velocity = vec2_mul(vec2_normalize(camera->move_velocity), max_move_speed); } // Number of seconds required for friction to stop movement completely. // (because velocity is sampled each frame, actual stop time longer than this) float stop_time = 0.1f; float inv_stop_time = 1.0f / stop_time; if (move_acceleration.x == 0.0f) camera->move_velocity.x -= camera->move_velocity.x * inv_stop_time * dt; if (move_acceleration.y == 0.0f) camera->move_velocity.y -= camera->move_velocity.y * inv_stop_time * dt; // r = r0 + (v0*t) + (a*t^2)/2 camera->position = vec2_add(vec2_add(camera->position, vec2_mul(camera->move_velocity, dt)), vec2_div(vec2_mul(move_acceleration, dt * dt), 2.0f)); // // zoom // float zoom_acceleration = 0.0f; if (key_down(GLFW_KEY_SPACE, input)) zoom_acceleration += 1.0f; if (key_down(GLFW_KEY_LEFT_CONTROL, input)) zoom_acceleration -= 1.0f; zoom_acceleration *= camera->zoom * 50.0f; if (zoom_acceleration == 0.0f) camera->zoom_velocity -= camera->zoom_velocity * (1.0f / 0.1f) * dt; // v = v0 + (a*t) camera->zoom_velocity += zoom_acceleration * dt; // r = r0 + (v0*t) + (a*t^2)/2 camera->zoom += (camera->zoom_velocity * dt) + (zoom_acceleration * dt * dt) / 2.0f; // Clamp zoom velocity. const float max_zoom_speed = 3.0f * camera->zoom; camera->zoom_velocity = clamp_float(camera->zoom_velocity, -max_zoom_speed, max_zoom_speed); float unclamped_zoom = camera->zoom; camera->zoom = clamp_float(camera->zoom, 1.0f, 1000.0f); if (camera->zoom != unclamped_zoom) camera->zoom_velocity = 0.0f; }