#include "handmade.h" #include "handmade_math.h" #include "sdl_handmade.h" #include "handmade_intrinsics.h" #include "handmade_random.h" #include "handmade_tile.h" #include "handmade_tile.c" #include #include /* malloc */ #include /* memset */ #include static void game_output_sound(struct game_state *game_state, struct game_sound_output_buffer *sound_buffer, int tone_hz) { /* short tone_volume, *sample_out; int wave_period, sample_index; tone_volume = 0; wave_period = sound_buffer->SamplesPerSecond / tone_hz; sample_out = sound_buffer->Samples; for(sample_index = 0; sample_index < sound_buffer->SampleCount; sample_index++) { float SineValue; short SampleValue; SineValue = sinf(game_state->tSine); SampleValue = (short)(SineValue * tone_volume); *sample_out++ = SampleValue; *sample_out++ = SampleValue; game_state->tSine += 2.0f * (float)PI * 1.0f / (float)wave_period; if(game_state->tSine > 2.0f*(float)PI) { game_state->tSine -= 2.0f*(float)PI; } } */ } static void clear_background(struct game_offscreen_buffer *buffer) { int width = buffer->width; int height = buffer->height; int x; for(x = 0; x < width * height; x++) { unsigned int *pixel = &((unsigned int *)buffer->memory)[x]; *pixel = 0xFFFFFF; } } static void draw_rectangle(struct game_offscreen_buffer *buffer, struct v2 v_min, struct v2 v_max, float r, float g, float b) { int y, x; int width, height; int min_x, min_y, max_x, max_y; unsigned int color; unsigned char *row; unsigned int *pixel; min_x = round_float_to_int(v_min.x); min_y = round_float_to_int(v_min.y); max_x = round_float_to_int(v_max.x); max_y = round_float_to_int(v_max.y); width = buffer->width; height = buffer->height; if(min_x < 0) min_x = 0; if(min_y < 0) min_y = 0; if(max_x > width) max_x = width; if(max_y > height) max_y = height; /*unsigned int color = (unsigned int)((round_float_to_int(r * 255.0f) << 16) | (round_float_to_int(g * 255.0f) << 8) | (round_float_to_int(b * 255.0f) << 0));*/ color = (unsigned int)((round_float_to_int(255.0f) << 24) | (round_float_to_int(r * 255.0f) << 16) | (round_float_to_int(g * 255.0f) << 8) | (round_float_to_int(b * 255.0f) << 0)); row = ((unsigned char *)buffer->memory + min_x*buffer->bytes_per_pixel + min_y*buffer->pitch); for(y = min_y; y < max_y; y++) { pixel = (unsigned int *)row; for(x = min_x; x < max_x; x++) { *(unsigned int *)pixel = color; pixel++; } row += buffer->pitch; } } static void draw_bitmap(struct game_offscreen_buffer *buffer, struct loaded_bitmap *bitmap, float rel_x, float rel_y, int align_x, int align_y) { int min_x, min_y, max_x, max_y; int width, height; int source_offset_x, source_offset_y; unsigned int *source_row; unsigned char *dest_row; int y, x; rel_x -= (float)align_x; rel_y -= (float)align_y; min_x = round_float_to_int(rel_x); min_y = round_float_to_int(rel_y); max_x = round_float_to_int(rel_x + (float)bitmap->width); max_y = round_float_to_int(rel_y + (float)bitmap->height); width = buffer->width; height = buffer->height; source_offset_x = 0; if(min_x < 0) { source_offset_x = -min_x; min_x = 0; } source_offset_y = 0; if(min_y < 0) { source_offset_y = -min_y; min_y = 0; } if(max_x > width) max_x = width; if(max_y > height) max_y = height; source_row = bitmap->pixels + bitmap->width*(bitmap->height - 1); source_row += -bitmap->width*source_offset_y + source_offset_x; dest_row = ((unsigned char *)buffer->memory + min_x*buffer->bytes_per_pixel + min_y*buffer->pitch); for(y = min_y; y < max_y; y++) { unsigned int *dest = (unsigned int *)dest_row; unsigned int *source = source_row; for(x = min_x; x < max_x; x++) { float sa = (float)((*source >> 24) & 0xFF); float sr = (float)((*source >> 16) & 0xFF); float sg = (float)((*source >> 8) & 0xFF); float sb = (float)((*source >> 0) & 0xFF); float da = (float)((*dest >> 24) & 0xFF); float dr = (float)((*dest >> 16) & 0xFF); float dg = (float)((*dest >> 8) & 0xFF); float db = (float)((*dest >> 0) & 0xFF); float ar = sa / 255.0f; /* TODO: This should be replaced by premultiplied alpha. */ float a = (1.0f-ar)*da + ar*sa; float r = (1.0f-ar)*dr + ar*sr; float g = (1.0f-ar)*dg + ar*sg; float b = (1.0f-ar)*db + ar*sb; *dest = (((unsigned int)round_float_to_int(a) << 24) | ((unsigned int)round_float_to_int(r) << 16) | ((unsigned int)round_float_to_int(g) << 8) | ((unsigned int)round_float_to_int(b) << 0)); dest++; source++; } dest_row += buffer->pitch; source_row -= bitmap->width; } } #pragma pack(push, 1) struct bitmap_header { unsigned short file_type; unsigned int file_size; unsigned short reserved1; unsigned short reserved2; unsigned int bitmap_offset; unsigned int size; int width; int height; unsigned short planes; unsigned short bits_per_pixel; unsigned int compression; unsigned int size_of_bitmap; int horz_resolution; int vert_resolution; unsigned int colors_used; unsigned int colors_important; unsigned int red_mask; unsigned int green_mask; unsigned int blue_mask; }; #pragma pack(pop) static struct loaded_bitmap debug_load_bmp(struct thread_context *thread, struct debug_read_file_result (*debug_platform_read_entire_file)(struct thread_context *thread, const char *), char *file_name) { struct loaded_bitmap result; struct debug_read_file_result read_result; memset(&result, 0, sizeof(result)); read_result = debug_platform_read_entire_file(thread, file_name); if(read_result.contents_size > 0) { struct bitmap_header *header; unsigned int *pixels; unsigned int red_mask, green_mask, blue_mask, alpha_mask; struct bit_scan_result red_shift, green_shift, blue_shift, alpha_shift; unsigned int *source_dest; int x, y; header = (struct bitmap_header *)read_result.contents; pixels = (unsigned int *)((unsigned char *)read_result.contents + header->bitmap_offset); result.pixels = pixels; result.width = header->width; result.height = header->height; assert(header->compression == 3); /* NOTE: The byte order in memory is determined by the header. */ red_mask = header->red_mask; green_mask = header->green_mask; blue_mask = header->blue_mask; alpha_mask = ~(red_mask | green_mask | blue_mask); red_shift = find_least_significant_set_bit(red_mask); green_shift = find_least_significant_set_bit(green_mask); blue_shift = find_least_significant_set_bit(blue_mask); alpha_shift = find_least_significant_set_bit(alpha_mask); assert(red_shift.found); assert(green_shift.found); assert(blue_shift.found); assert(alpha_shift.found); source_dest = pixels; for(y = 0; y < header->height; y++) { for(x = 0; x < header->width; x++) { unsigned int c = *source_dest; *source_dest = ((((c >> alpha_shift.index) & 0xFF) << 24) | (((c >> red_shift.index ) & 0xFF) << 16) | (((c >> green_shift.index) & 0xFF) << 8) | (((c >> blue_shift.index ) & 0xFF) << 0)); source_dest++; } } } return result; } static struct entity *get_entity(struct game_state *game_state, unsigned int index) { struct entity *entity = NULL; if((index > 0) && (index < ARRAY_SIZE(game_state->entities))) { entity = &game_state->entities[index]; } return entity; } static void initialize_player(struct entity *entity) { entity->exists = 1; entity->p.abs_tile_x = 2; entity->p.abs_tile_y = 3; entity->p.offset.x = 5.0f; entity->p.offset.y = 5.0f; entity->height = 1.4f; entity->width = 0.75f * entity->height; } static unsigned int add_entity(struct game_state *game_state) { unsigned int entity_index = ++game_state->entity_count; struct entity *entity; assert(game_state->entity_count < ARRAY_SIZE(game_state->entities)); entity = &game_state->entities[entity_index]; memset(entity, 0, sizeof(struct entity)); return entity_index; } static void move_player(struct game_state *game_state, struct entity *entity, float dt, struct v2 dd_player) { struct tile_map *tile_map; float player_speed; struct tile_map_position old_player_p, new_player_p; struct v2 player_delta; tile_map = game_state->world->tile_map; if((dd_player.x != 0.0f) && (dd_player.y != 0.0f)) dd_player = V2Multiply(0.7071067811865475244f, dd_player); player_speed = 10.0f; dd_player = V2Multiply(player_speed, dd_player); dd_player = V2Add(dd_player, V2Unary(V2Multiply(1.5f, entity->dp))); old_player_p = entity->p; new_player_p = old_player_p; player_delta = V2Add(V2Multiply(0.5f, V2Multiply(Square(dt), dd_player)), V2Multiply(dt, entity->dp)); new_player_p.offset = V2Add(player_delta, new_player_p.offset); entity->dp = V2Add(V2Multiply(dt, dd_player), entity->dp); new_player_p = recannonicalize_position(tile_map, new_player_p); { #if 1 struct tile_map_position player_left, player_right; int collided; struct tile_map_position col_p; player_left = new_player_p; player_left.offset.x -= 0.5f*entity->width; player_left = recannonicalize_position(tile_map, player_left); player_right = new_player_p; player_right.offset.x += 0.5f*entity->width; player_right = recannonicalize_position(tile_map, player_right); collided = 0; memset(&col_p, 0, sizeof(col_p)); if(!is_tile_map_point_empty(tile_map, new_player_p)) { col_p = new_player_p; collided = 1; } if(!is_tile_map_point_empty(tile_map, player_left)) { col_p = player_left; collided = 1; } if(!is_tile_map_point_empty(tile_map, player_right)) { col_p = player_right; collided = 1; } if(collided) { struct v2 r = { 0, 0 }; if(col_p.abs_tile_x < entity->p.abs_tile_x) { r.x = 1; r.y = 0; } if(col_p.abs_tile_x > entity->p.abs_tile_x) { r.x = -1; r.y = 0; } if(col_p.abs_tile_y < entity->p.abs_tile_y) { r.x = 0; r.y = 1; } if(col_p.abs_tile_y > entity->p.abs_tile_y) { r.x = 0; r.y = -1; } entity->dp = V2Subtract(entity->dp, V2Multiply(1*InnerProduct(entity->dp, r), r)); } else { entity->p = new_player_p; } #else unsigned int MinTileX = 0; unsigned int MinTileY = 0; unsigned int OnePastMaxTileX = 0; unsigned int OnePastMaxTileY = 0; unsigned int abs_tile_z = game_state->PlayerP.abs_tile_z; tile_map_position BestPlayerP = game_state->PlayerP; F32 BestDistance = LengthSq(player_delta); for(unsigned int abs_tile_y = MinTileY; abs_tile_y != OnePastMaxTileY; abs_tile_y++) { for(unsigned int abs_tile_x = MinTileX; abs_tile_x != OnePastMaxTileX; abs_tile_x++) { tile_map_position TestTileP = CenteredTilePoint(abs_tile_x, abs_tile_y, abs_tile_z); unsigned int TileValue = get_tile_value_by_pos(tile_map, TestTileP); if(IsTileValueEmpty(TileValue)) { v2 MinCorner = V2Multiply(-0.5f, (v2){ tile_map->tile_side_in_meters, tile_map->tile_side_in_meters }); v2 MaxCorner = V2Multiply(-0.5f, (v2){ tile_map->tile_side_in_meters, tile_map->tile_side_in_meters }); tile_map_difference RelNewPlayerP = SubtractInF32(tile_map, &TestTileP, &new_player_p); v2 TestP = ClosestPointInRectangle(MinCorner, MaxCorner, RelNewPlayerP); if(...) { } } } } #endif } if(!are_on_same_tile(&old_player_p, &entity->p)) { unsigned int new_tile_value = get_tile_value_by_pos(tile_map, entity->p); if(new_tile_value == 3) { entity->p.abs_tile_z++; } else if(new_tile_value == 4) { entity->p.abs_tile_z--; } } if(absolute_value(dd_player.x) > absolute_value(dd_player.y)) { if(dd_player.x > 0) { entity->facing_direction = 0; } else { entity->facing_direction = 2; } } else if(absolute_value(dd_player.x) < absolute_value(dd_player.y)) { if(dd_player.y > 0) { entity->facing_direction = 1; } else { entity->facing_direction = 3; } } } void update_and_render(struct thread_context *thread, struct game_memory *memory, struct game_input *input, struct game_offscreen_buffer *buffer, struct game_sound_output_buffer *sound_buffer) { struct game_state *game_state; struct world *world; struct tile_map *tile_map; int tile_side_in_pixels; float meters_to_pixels; unsigned int controller_index; struct entity *camera_following_entity; float screen_center_x, screen_center_y; int rel_row, rel_column; struct entity *entity; unsigned int entity_index; assert((&input->controllers[0].u.s.terminator - &input->controllers[0].u.buttons[0]) == ARRAY_SIZE(input->controllers[0].u.buttons)); assert(sizeof(struct game_state) <= memory->permanent_storage_size); game_state = (struct game_state *)memory->permanent_storage; if(!memory->is_initialized) { struct hero_bitmaps *bitmap; struct world *world; struct tile_map *tile_map; unsigned int random_number_index; unsigned int tiles_per_width, tiles_per_height; unsigned int screen_x, screen_y; unsigned int abs_tile_z; int door_top, door_bottom, door_left, door_right, door_up, door_down; unsigned int screen_index; /* NOTE: Reserve entity slot 0 for null entity */ add_entity(game_state); game_state->rect_pos.x = 0.0f; game_state->rect_pos.y = 0.0f; game_state->program_icon.width = 256; game_state->program_icon.height = 256; game_state->program_icon.bytes_per_pixel = 4; game_state->program_icon.pitch = game_state->program_icon.bytes_per_pixel * game_state->program_icon.width; game_state->program_icon.memory = malloc(game_state->program_icon.bytes_per_pixel * game_state->program_icon.width * game_state->program_icon.height); memset(game_state->program_icon.memory, 0, game_state->program_icon.bytes_per_pixel * game_state->program_icon.width * game_state->program_icon.height); #if 0 game_state->ProgramIconBMP = debug_load_bmp(thread, memory->DEBUGPlatformReadEntireFile, "data/program_icon.bmp"); draw_bitmap(&game_state->ProgramIcon, &game_state->ProgramIconBMP, 0.0f, 0.0f, 0, 0); memory->SetProgramIcon(&game_state->ProgramIcon); #endif game_state->backdrop = debug_load_bmp(thread, memory->debug_platform_read_entire_file, "data/test_background.bmp"); bitmap = &game_state->hero_bitmaps[0]; bitmap->align_x = 72; bitmap->align_y = 182; bitmap->head = debug_load_bmp(thread, memory->debug_platform_read_entire_file, "data/test_hero_right_head.bmp"); bitmap->cape = debug_load_bmp(thread, memory->debug_platform_read_entire_file, "data/test_hero_right_cape.bmp"); bitmap->torso = debug_load_bmp(thread, memory->debug_platform_read_entire_file, "data/test_hero_right_torso.bmp"); bitmap++; bitmap->align_x = 72; bitmap->align_y = 182; bitmap->head = debug_load_bmp(thread, memory->debug_platform_read_entire_file, "data/test_hero_back_head.bmp"); bitmap->cape = debug_load_bmp(thread, memory->debug_platform_read_entire_file, "data/test_hero_back_cape.bmp"); bitmap->torso = debug_load_bmp(thread, memory->debug_platform_read_entire_file, "data/test_hero_back_torso.bmp"); bitmap++; bitmap->align_x = 72; bitmap->align_y = 182; bitmap->head = debug_load_bmp(thread, memory->debug_platform_read_entire_file, "data/test_hero_left_head.bmp"); bitmap->cape = debug_load_bmp(thread, memory->debug_platform_read_entire_file, "data/test_hero_left_cape.bmp"); bitmap->torso = debug_load_bmp(thread, memory->debug_platform_read_entire_file, "data/test_hero_left_torso.bmp"); bitmap++; bitmap->align_x = 72; bitmap->align_y = 182; bitmap->head = debug_load_bmp(thread, memory->debug_platform_read_entire_file, "data/test_hero_front_head.bmp"); bitmap->cape = debug_load_bmp(thread, memory->debug_platform_read_entire_file, "data/test_hero_front_cape.bmp"); bitmap->torso = debug_load_bmp(thread, memory->debug_platform_read_entire_file, "data/test_hero_front_torso.bmp"); game_state->camera_p.abs_tile_x = 17 / 2; game_state->camera_p.abs_tile_y = 9 / 2; InitializeArena(&game_state->world_arena, memory->permanent_storage_size - sizeof(struct game_state), (unsigned char *)memory->permanent_storage + sizeof(struct game_state)); game_state->world = PUSH_STRUCT(&game_state->world_arena, struct world); world = game_state->world; world->tile_map = PUSH_STRUCT(&game_state->world_arena, struct tile_map); tile_map = world->tile_map; tile_map->chunk_shift = 4; tile_map->chunk_mask = (1 << tile_map->chunk_shift) - 1; tile_map->chunk_dim = (1 << tile_map->chunk_shift); tile_map->tile_chunk_count_x = 128; tile_map->tile_chunk_count_y = 128; tile_map->tile_chunk_count_z = 2; tile_map->tile_chunks = PUSH_ARRAY(&game_state->world_arena, tile_map->tile_chunk_count_x * tile_map->tile_chunk_count_y * tile_map->tile_chunk_count_z, struct tile_chunk); tile_map->tile_side_in_meters = 1.4f; random_number_index = 0; tiles_per_width = 17; tiles_per_height = 9; screen_x = 0; screen_y = 0; abs_tile_z = 0; door_top = 0; door_bottom = 0; door_left = 0; door_right = 0; door_up = 0; door_down = 0; for(screen_index = 0; screen_index < 100; screen_index++) { /* TODO: Random number generator. */ unsigned int random_choice; int created_z_door; unsigned int tile_y, tile_x; assert(random_number_index < ARRAY_SIZE(random_number_table)); if(door_up || door_down) { random_choice = random_number_table[random_number_index++] % 2; } else { random_choice = random_number_table[random_number_index++] % 3; } created_z_door = 0; if(random_choice == 2) { created_z_door = 1; if(abs_tile_z == 0) { door_up = 1; } else { door_down = 1; } } else if(random_choice == 1) { door_right = 1; } else { door_top = 1; } for(tile_y = 0; tile_y < tiles_per_height; tile_y++) { for(tile_x = 0; tile_x < tiles_per_width; tile_x++) { unsigned int abs_tile_x = screen_x * tiles_per_width + tile_x; unsigned int abs_tile_y = screen_y * tiles_per_height + tile_y; unsigned int TileValue = 1; if(tile_x == 0 && (!door_left || (tile_y != (tiles_per_height/2)))) { TileValue = 2; } if(tile_x == (tiles_per_width - 1) && (!door_right || (tile_y != (tiles_per_height/2)))) { TileValue = 2; } if(tile_y == 0 && (!door_bottom || (tile_x != (tiles_per_width/2)))) { TileValue = 2; } if(tile_y == (tiles_per_height - 1) && (!door_top || (tile_x != (tiles_per_width/2)))) { TileValue = 2; } if((tile_x == 10) && (tile_y == 6)) { if(door_up) { TileValue = 3; } if(door_down) { TileValue = 4; } } set_tile_value(&game_state->world_arena, world->tile_map, abs_tile_x, abs_tile_y, abs_tile_z, TileValue); } } door_left = door_right; door_bottom = door_top; if(created_z_door) { door_down = !door_down; door_up = !door_up; } else { door_up = 0; door_down = 0; } door_top = 0; door_right = 0; if(random_choice == 2) { if(abs_tile_z == 0) { abs_tile_z = 1; } else { abs_tile_z = 0; } } else if(random_choice == 1) { screen_x++; } else { screen_y++; } } memory->is_initialized = 1; } world = game_state->world; tile_map = world->tile_map; tile_side_in_pixels = 60; meters_to_pixels = (float)tile_side_in_pixels / tile_map->tile_side_in_meters; for(controller_index = 0; controller_index < ARRAY_SIZE(input->controllers); controller_index++) { struct game_controller_input *Controller; struct entity *ControllingEntity; Controller = GetController(input, controller_index); ControllingEntity = get_entity(game_state, game_state->player_index_for_controller[controller_index]); if(ControllingEntity) { struct v2 dd_player; /* accerlation */ memset(&dd_player, 0, sizeof(dd_player)); if(Controller->is_analog) { dd_player.x = Controller->stick_average_x; dd_player.y = -Controller->stick_average_y; } else { if(Controller->u.s.move_up.ended_down) { game_state->rect_pos.y -= 1.0f; dd_player.y = 1.0f; } if(Controller->u.s.move_down.ended_down) { game_state->rect_pos.y += 1.0f; dd_player.y = -1.0f; } if(Controller->u.s.move_left.ended_down) { game_state->rect_pos.x -= 1.0f; dd_player.x = -1.0f; } if(Controller->u.s.move_right.ended_down) { game_state->rect_pos.x += 1.0f; dd_player.x = 1.0f; } } move_player(game_state, ControllingEntity, input->dt_for_frame, dd_player); } else { if(Controller->u.s.start.ended_down) { unsigned int entity_index = add_entity(game_state); ControllingEntity = get_entity(game_state, entity_index); initialize_player(ControllingEntity); game_state->player_index_for_controller[controller_index] = entity_index; } } } camera_following_entity = get_entity(game_state, game_state->camera_following_entity_index); if(camera_following_entity) { struct tile_map_difference diff; game_state->camera_p.abs_tile_z = camera_following_entity->p.abs_tile_z; diff = subtract_in_float(tile_map, &camera_following_entity->p, &game_state->camera_p); if(diff.d_xy.x > (9.0f*tile_map->tile_side_in_meters)) { game_state->camera_p.abs_tile_x += 17; } if(diff.d_xy.x < -(9.0f*tile_map->tile_side_in_meters)) { game_state->camera_p.abs_tile_x -= 17; } if(diff.d_xy.y > (5.0f*tile_map->tile_side_in_meters)) { game_state->camera_p.abs_tile_y += 9; } if(diff.d_xy.y < -(5.0f*tile_map->tile_side_in_meters)) { game_state->camera_p.abs_tile_y -= 9; } } /*draw_rectangle(buffer, 0.0f, 0.0f, (F32)buffer->Width, (F32)buffer->Height, 0.0f, 1.0f, 0.0f);*/ draw_bitmap(buffer, &game_state->backdrop, 0.0f, 0.0f, 0, 0); screen_center_x = 0.5f * (float)buffer->width; screen_center_y = 0.5f * (float)buffer->height; for(rel_row = -10; rel_row < 10; rel_row++) { for(rel_column = -20; rel_column < 20; rel_column++) { unsigned int Column = game_state->camera_p.abs_tile_x + rel_column; unsigned int row = game_state->camera_p.abs_tile_y + rel_row; unsigned int TileID = get_tile_value(tile_map, Column, row, game_state->camera_p.abs_tile_z); if(TileID > 1) { struct v2 TileSide, Center; struct v2 Min, Max; float Gray = 0.5f; if(TileID == 2) { Gray = 1.0f; } if(TileID > 2) { Gray = 0.25f; } if(Column == game_state->camera_p.abs_tile_x && row == game_state->camera_p.abs_tile_y) { Gray = 0.0f; } TileSide.x = 0.5f*(float)tile_side_in_pixels; TileSide.y = 0.5f*(float)tile_side_in_pixels; Center.x = screen_center_x - meters_to_pixels*game_state->camera_p.offset.x + (float)rel_column*(float)tile_side_in_pixels; Center.y = screen_center_y + meters_to_pixels * game_state->camera_p.offset.y - (float)rel_row*(float)tile_side_in_pixels; Min = V2Subtract(Center, TileSide); Max = V2Add(Center, TileSide); draw_rectangle(buffer, Min, Max, Gray, Gray, Gray); } } } entity = game_state->entities; for(entity_index = 0; entity_index < game_state->entity_count; entity_index++, entity++) { if(entity->exists) { struct tile_map_difference diff; float player_r, player_g, player_b; float player_ground_point_x, player_ground_point_y; struct v2 player_left_top, player_width_height; struct hero_bitmaps *bitmap; diff = subtract_in_float(tile_map, &entity->p, &game_state->camera_p); player_r = 1.0f; player_g = 0.0f; player_b = 0.0f; player_ground_point_x = screen_center_x + meters_to_pixels*diff.d_xy.x; player_ground_point_y = screen_center_y - meters_to_pixels*diff.d_xy.y; player_left_top.x = player_ground_point_x - 0.5f * meters_to_pixels*entity->width; player_left_top.y = player_ground_point_y - meters_to_pixels*entity->height; player_width_height.x = entity->width; player_width_height.x = entity->height; draw_rectangle(buffer, player_left_top, V2Add(player_left_top, V2Multiply(meters_to_pixels, player_width_height)), player_r, player_g, player_b); bitmap = &game_state->hero_bitmaps[entity->facing_direction]; draw_bitmap(buffer, &bitmap->torso, player_ground_point_x, player_ground_point_y, bitmap->align_x, bitmap->align_y); draw_bitmap(buffer, &bitmap->cape, player_ground_point_x, player_ground_point_y, bitmap->align_x, bitmap->align_y); draw_bitmap(buffer, &bitmap->head, player_ground_point_x, player_ground_point_y, bitmap->align_x, bitmap->align_y); /* TODO: Remove this. */ /*draw_rectangle(&game_state->ProgramIcon, game_state->rect_pos, (struct v2){ game_state->rect_pos.X + 20.0f, game_state->rect_pos.Y + 20.0f }, 0.8f, 0.8f, 0.8f);*/ /*memory->SetProgramIcon(&game_state->ProgramIcon);*/ } } game_output_sound(game_state, sound_buffer, 400); } /* static void RenderWeirdGradient(game_offscreen_buffer *buffer, int XOffset, int YOffset) { int Width, Height, Y; U8 *row; Width = buffer->Width; Height = buffer->Height; row = (U8 *)buffer->memory; for(Y = 0; Y < Height; Y++) { unsigned int *pixel = (unsigned int *)row; int X; pixel = (unsigned int *)row; for(X = 0; X < Width; X++) { U8 Blue, Green; Blue = (U8)(X + XOffset); Green = (U8)(Y + YOffset); *pixel = (Green << 8) | Blue; pixel++; } row += buffer->Pitch; } } */