Esempio n. 1
0
INTERNAL v2 calculateProjectionRangeForEdge(v2 *vertexList, i32 vertexListSize,
                                            v2 edgeNormal)
{
	v2 result  = {0};
	result.min = v2_dot(vertexList[0], edgeNormal);
	result.max = result.min;

	for (i32 vertexIndex = 0; vertexIndex < vertexListSize; vertexIndex++)
	{
		f32 dist = v2_dot(vertexList[vertexIndex], edgeNormal);

		if (dist < result.min)
			result.min = dist;
		else if (dist > result.max)
			result.max = dist;
	}

	return result;
}
Esempio n. 2
0
scalar_t noise2(scalar_t x, scalar_t y)
{
	int i, j, b00, b10, b01, b11;
	int bx0, bx1, by0, by1;
	scalar_t rx0, rx1, ry0, ry1;
	scalar_t sx, sy, u, v, a, b;

	if(!tables_valid) {
		init_noise();
		tables_valid = 1;
	}

	setup(x, bx0, bx1, rx0, rx1);
	setup(y, by0, by1, ry0, ry1);

	i = perm[bx0];
	j = perm[bx1];

	b00 = perm[i + by0];
	b10 = perm[j + by0];
	b01 = perm[i + by1];
	b11 = perm[j + by1];

	/* calculate hermite inteprolating factors */
	sx = s_curve(rx0);
	sy = s_curve(ry0);

	/* interpolate along the left edge */
	u = v2_dot(grad2[b00], v2_cons(rx0, ry0));
	v = v2_dot(grad2[b10], v2_cons(rx1, ry0));
	a = lerp(u, v, sx);

	/* interpolate along the right edge */
	u = v2_dot(grad2[b01], v2_cons(rx0, ry1));
	v = v2_dot(grad2[b11], v2_cons(rx1, ry1));
	b = lerp(u, v, sx);

	/* interpolate between them */
	return lerp(a, b, sy);
}
Esempio n. 3
0
void update_world_area(World_Area* area)
{
	game_set_scale(2.0);
	real movespeed = 800;
	Vec2 move_impulse = v2(0, 0);

	if(_check(LEFT, A, State_Pressed)) {
		move_impulse.x -= movespeed;
	}
	if(_check(RIGHT, D, State_Pressed)) {
		move_impulse.x += movespeed;
	}
	if(_check(UP, W, State_Pressed)) {
		move_impulse.y -= movespeed;
	}
	if(_check(DOWN, S, State_Pressed)) {
		move_impulse.y += movespeed;
	}

	if(fabsf(move_impulse.x * move_impulse.y) > 0.01f) {
		move_impulse *= Math_InvSqrt2;
	}

	play_state->current_time = SDL_GetTicks();
	real dt = (play_state->current_time - play_state->prev_time) / 1000.0;
	dt = clamp(dt, 0, 1.2f);
	play_state->accumulator += dt;
	play_state->prev_time = play_state->current_time;

	sim_sort_bodies_on_id(&area->sim);
	Entity* player_entity = world_area_find_entity(area, 0);
	Sim_Body* player = player_entity->body;

	Tile_Info* player_tile = area->map.info + tilemap_get_at(&area->map, player->shape.center);

	move_impulse *= player_tile->movement_modifier;


	while(play_state->accumulator >= Time_Step) {
		play_state->accumulator -= Time_Step;
		player->velocity += move_impulse;
		sim_update(&area->sim, &area->map, Time_Step);
	}

	Direction old_direction = player_entity->direction;
	if(move_impulse.y < 0) {
		player_entity->direction = Direction_North;
	} else if(move_impulse.y > 0) {
		player_entity->direction = Direction_South;
	}

	if(move_impulse.x < 0) {
		player_entity->facing = -1;
		player_entity->direction = Direction_West;
	} else if(move_impulse.x > 0) {
		player_entity->facing = 1;
		player_entity->direction = Direction_East;
	}
	if(input->scancodes[SDL_SCANCODE_SPACE] == State_Pressed) {
		player_entity->direction = old_direction;
	}
	Sprite* plr_spr = &player_entity->sprite;
	int32 player_frame = 0;
	if(v2_dot(move_impulse, move_impulse) > 0){
		player_entity->counter++;
		player_frame = 1;
		if(player_entity->counter > 15) {
			player_frame = 0;
			if(player_entity->counter > 30) {
				player_entity->counter = 0;
			}
		}
	} else {
		player_entity->counter = 0;
		player_frame = 0;
	}

	if(player_entity->facing == -1) {
		plr_spr->texture = Get_Texture_Coordinates(32 + player_frame * 32, 0, -32, 32);
	} else if(player_entity->facing == 1) {
		plr_spr->texture = Get_Texture_Coordinates(0  + player_frame * 32, 0, 32, 32);
	}

	Vec2 target = player->shape.center;

	if(target.x < 0) {
		world_switch_current_area(play_state->world, area->west);
		play_state->world_xy.x--;
	} else if(target.x > area->map.w * Tile_Size) {
		world_switch_current_area(play_state->world, area->east);
		play_state->world_xy.x++;
	} else if(target.y < 0) {
		world_switch_current_area(play_state->world, area->north);
		play_state->world_xy.y--;
	} else if(target.y > area->map.h * Tile_Size) {
		world_switch_current_area(play_state->world, area->south);
		play_state->world_xy.y++;
	}

	area->offset += (target - area->offset) * 0.1f;
	area->offset -= game->size * 0.5f;
	if(area->offset.x < 0) 
		area->offset.x = 0;
	else if((area->offset.x + game->size.x) > area->map.w * Tile_Size)
		area->offset.x = area->map.w * Tile_Size - game->size.x;

	if(area->offset.y < 0) 
		area->offset.y = 0;
	else if((area->offset.y + game->size.y) > area->map.h * Tile_Size)
		area->offset.y = area->map.h * Tile_Size - game->size.y;

	//TODO(will) refactor into own function?
	/*
	 * Player input code
	 *
	 */ 
	if(input->mouse[SDL_BUTTON_LEFT] == State_Just_Pressed) {
		Entity* ball_entity = world_area_get_next_entity(area);
		Sim_Body* ball = ball_entity->body;
		Vec2 dmouse = v2(input->mouse_x / game->scale, 
						input->mouse_y / game->scale) + area->offset;

		dmouse -= player->shape.center;
		real angle = atan2f(dmouse.y, dmouse.x);
		Vec2 normal = v2(cosf(angle), sinf(angle));
		entity_add_event_on_activate(ball_entity, delete_on_activate);

		ball->damping = 0.9999f;
		ball->shape.hext = v2(8, 16);
		ball->shape.center = normal * ball->shape.hw * 4 + player->shape.center; 
		ball->velocity += normal * 2000;
		ball->shape.hext = v2(8, 6);
		//ball->flags = Body_Flag_No_Friction;
		ball_entity->sprite.size = v2(16, 32);
		ball_entity->sprite.center = v2(0, 10);
		ball_entity->sprite.texture  = Get_Texture_Coordinates(0, 96, 32, 64);
	}


	if(input->mouse[SDL_BUTTON_RIGHT] == State_Just_Pressed) {
		Vec2 dmouse = v2(
			input->mouse_x / game->scale, 
			input->mouse_y / game->scale) + area->offset;
		AABB mbb = aabb(dmouse, 0, 0);
		world_area_synchronize_entities_and_bodies(area);
		for(isize i = 0; i < area->entities_count; ++i) {
			Entity* e = area->entities + i;
			if(aabb_intersect(e->body->shape, mbb)) {
				if(e->id != 0) {
					for(isize j = 0; j < e->event_on_activate_count; ++j) {
						e->event_on_activate[j](e, area);
					}
					break;
				}
			}
		}
	}

	if(input->scancodes[SDL_SCANCODE_F] == State_Just_Pressed) {
		//tilemap_set_at(&area->map, player->shape.center, Tile_Dug_Earth);
		Tile_State* state = tilemap_get_state_at(&area->map, player->shape.center);
		if(state != NULL) {
			state->damage++;
			update_tile_state_at(&area->map, player->shape.center);
		}
	}

	Sprite s;

	if(input->scancodes[SDL_SCANCODE_SPACE] >= State_Pressed) {
		init_sprite(&s);
		s.position = player->shape.center;
		s.size = v2(16, 16);
		s.texture = Get_Texture_Coordinates(0, renderer->texture_height - 16, 16, 16);
		s.color = v4(1, 1, 1, 1);
		switch(player_entity->direction) {
			case Direction_North:
				s.position.y -= s.size.y + player->shape.hh;
				break;
			case Direction_South:
				s.position.y += s.size.y + player->shape.hh;
				break;
			case Direction_East:
				s.position.x += s.size.x + player->shape.hw;
				break;
			case Direction_West:
				s.position.x -= s.size.x + player->shape.hh;
				break;
		}

		if(input->scancodes[SDL_SCANCODE_SPACE] == State_Just_Pressed) {
			//TODO(will) implement good space queries	
			Sim_Body* touching = sim_query_aabb(&area->sim, 
					aabb(s.position, s.size.x / 2, s.size.y / 2));
			if(touching != NULL) {
				if(!Has_Flag(touching->flags, Body_Flag_Static)) 
					player_entity->held_entity_id = touching->entity_id;
			}
		}
	} else {
		player_entity->held_entity_id = -1;
	}

	char debug_str[256];
	if(player_entity->held_entity_id > 0) {
		Entity* e = world_area_find_entity(area, player_entity->held_entity_id);
		if(e != NULL) {
			Sim_Body* b = e->body;
			Vec2 target = player->shape.center; 
			Vec2 diff = b->shape.hext + player->shape.hext + v2(8, 8);
			switch(player_entity->direction) {
				case Direction_North:
					target.y -= diff.y;
					break;
				case Direction_South:
					target.y += diff.y;
					break;
				case Direction_East:
					target.x += diff.x;
					break;
				case Direction_West:
					target.x -= diff.x;
					break;
			}
			
			Vec2 impulse = (target - b->shape.center);
			if(v2_dot(impulse, impulse) > (4 * Tile_Size * Tile_Size)) {
				player_entity->held_entity_id = -1;
			}
			impulse *= 60;
			{
				snprintf(debug_str, 256, "T(%.2f %.2f) j(%.2f %.2f)", target.x, target.y,
						impulse.x, impulse.y);

			}
			if(v2_dot(impulse, impulse) < (1000 * 1000)) 
				b->velocity += impulse;// * b->inv_mass;

		}

	}

	renderer->offset = area->offset;
	area->offset += game->size * 0.5f;
	// throw a ball

	renderer_start();

	Rect2 screen = rect2(
			area->offset.x - game->size.x / 2,
			area->offset.y - game->size.y / 2, 
			game->size.x, game->size.y);

	isize sprite_count_offset = render_tilemap(&area->map, v2(0,0), screen);

	for(isize i = 0; i < area->entities_count; ++i) {
		Entity* e = area->entities + i;
		Sim_Body* b = sim_find_body(&area->sim, e->body_id);

		if (b == NULL) continue;
		e->sprite.position = b->shape.center;
		//e->sprite.size = v2(b->shape.hw * 2, b->shape.hh * 2);
		
		//TODO(will) align entity sprites by their bottom center
		renderer_push_sprite(&e->sprite);
	}

	renderer_push_sprite(&s);
	renderer_sort(sprite_count_offset);

	renderer_draw();

	renderer->offset = v2(0, 0);
	game_set_scale(1.0);
	renderer_start();

	char str[256];
	isize len = snprintf(str, 256, "X:%d Y:%d Tile: %s",
			play_state->world_xy.x, 
			play_state->world_xy.y, 
			player_tile->name);

	render_body_text(str, v2(16, game->size.y - (body_font->glyph_height) - 8), true);
	render_body_text(debug_str, v2(16, 16), true);

	renderer_draw();
}
void sim_update(Simulator* sim, Tilemap* map, real dt)
{
	Sim_Body *a, *b;
	for(isize times = 0; times < Sim_Iter_i; ++times) {
//#if 0
		if(sim->sort_axis == 0) {
			body_sort_on_x(sim->bodies, sim->bodies_count);
		} else if(sim->sort_axis == 1) {
			body_sort_on_y(sim->bodies, sim->bodies_count);
		}

//#endif 
		Vec2 center_sum1 = v2(0, 0);
		Vec2 center_sum2 = v2(0, 0);
		Vec2 variance = v2(0, 0);
		for(isize i = 0; i < sim->bodies_count; ++i) {
			a = sim->bodies + i;

			//sweep and prune stuff
			center_sum1 += a->shape.center;
			for(isize q = 0; q < 2; ++q) {
				center_sum2.e[q] += a->shape.center.e[q] * a->shape.center.e[q];
			}

			//if(a->is_static) continue;

			for(isize j = i + 1; j < sim->bodies_count; ++j) {
				b = sim->bodies + j;

				uint64 a_is_static = Has_Flag(a->flags, Body_Flag_Static);
				uint64 b_is_static = Has_Flag(b->flags, Body_Flag_Static);
				if(a_is_static && b_is_static) continue;

//#if 0
				if(sim->sort_axis == 0) {
					if(AABB_x1(b->shape) > AABB_x2(a->shape)) {
						break;
					}
				} else if(sim->sort_axis == 1) {
					if(AABB_y1(b->shape) > AABB_y2(a->shape)) {
						break;
					}
				}
//#endif 
			
				if(aabb_intersect(&a->shape, &b->shape)) {
					Vec2 overlap;
					aabb_overlap(&a->shape, &b->shape, &overlap);
					real ovl_mag = sqrtf(v2_dot(overlap, overlap));
					if (ovl_mag < 0.0001f) continue;
					Vec2 normal = overlap * (1.0f / ovl_mag);

					if(a->id == 0 || b->id  == 0) {
						aabb_intersect(&a->shape, &b->shape);
					}
					

					#define _collision_slop (0.8f)
					if(a_is_static && !b_is_static) {
						b->shape.center += overlap;
						Vec2 relative_velocity = b->velocity;
						real velocity_on_normal = v2_dot(relative_velocity, normal);
						if(velocity_on_normal > 0) continue;

						real e = Min(a->restitution, b->restitution);
						real mag = -1.0f * (1.0f + e) * velocity_on_normal;
						mag /= b->inv_mass;
						Vec2 impulse = mag * normal;
						b->collision_vel += b->inv_mass * impulse;
					} else if(!a_is_static && b_is_static) {
						a->shape.center -= overlap;

						Vec2 relative_velocity = -a->velocity;
						real velocity_on_normal = v2_dot(relative_velocity, normal);
						if(velocity_on_normal > 0) continue;

						real e = Min(a->restitution, b->restitution);
						real mag = -1.0f * (1.0f + e) * velocity_on_normal;
						mag /= a->inv_mass + 0;
						Vec2 impulse = mag * normal;
						a->collision_vel -= a->inv_mass * impulse;
					} else {
						Vec2 separation = Max(ovl_mag - _collision_slop, 0) 
							* (1.0f / (a->inv_mass + b->inv_mass)) * 0.5f * normal;
						a->shape.center -= a->inv_mass * separation;
						b->shape.center += b->inv_mass * separation;

						Vec2 relative_velocity = b->velocity - a->velocity;
						real velocity_on_normal = v2_dot(relative_velocity, normal);
						if(velocity_on_normal > 0) continue;

						real e = Min(a->restitution, b->restitution);
						real mag = -1.0f * (1.0f + e) * velocity_on_normal;
						mag /= a->inv_mass + b->inv_mass;
						Vec2 impulse = mag * normal;
						a->collision_vel -= a->inv_mass * impulse;
						b->collision_vel += b->inv_mass * impulse;
					}
				}
			}
		}

		for(isize i = 0; i < 2; ++i) {
			variance.e[i] = center_sum2.e[i] - center_sum1.e[i] * center_sum1.e[i] / 
				sim->bodies_count;
		}
		
		if(variance.x > variance.y) {
			sim->sort_axis = 0;
		} else {
			sim->sort_axis = 1;
		}

		for(isize i = 0; i < sim->bodies_count; ++i) {
			a = sim->bodies + i;
			if(Has_Flag(a->flags, Body_Flag_Static)) continue;
			Vec2 iter_acl = (a->force * a->inv_mass) / Sim_Iter;
			Vec2 new_vel = a->velocity + (dt * iter_acl);
			Vec2 dpos = (a->velocity + new_vel) * 0.5f;
			dpos *= 1.0f / Sim_Iter;
			a->shape.center += dpos * dt;
			a->shape.center += a->collision_vel / Sim_Iter * dt;
			a->velocity = new_vel;
			Tile_Info* tile = map->info + tilemap_get_at(map, a->shape.center);
			real damping = 1.0f;
			if(Has_Flag(a->flags, Body_Flag_No_Friction)) {
				damping = a->damping;
			} else {
				damping = sqrtf(a->damping * a->damping + 
					tile->friction * tile->friction) * Math_InvSqrt2;
			}
			a->velocity *= powf(damping, Sim_Iter);
			a->velocity += a->collision_vel;
			a->collision_vel = v2(0, 0);
		}

	}
	body_sort_on_id(sim->bodies, sim->bodies_count);
}