Files
2026-08-07 12:28:18 -07:00

992 lines
32 KiB
C

#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 <stdio.h>
#include <stdlib.h> /* malloc */
#include <string.h> /* memset */
#include <assert.h>
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;
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 = v2_multiply(0.7071067811865475244f, dd_player);
player_speed = 10.0f;
dd_player = v2_multiply(player_speed, dd_player);
dd_player = v2_add(dd_player, v2_unary(v2_multiply(1.5f, entity->dp)));
old_player_p = entity->p;
new_player_p = old_player_p;
player_delta = v2_add(v2_multiply(0.5f, v2_multiply(square(dt), dd_player)),
v2_multiply(dt, entity->dp));
new_player_p.offset = v2_add(player_delta, new_player_p.offset);
entity->dp = v2_add(v2_multiply(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 = v2_subtract(entity->dp,
v2_multiply(1*inner_product(entity->dp, r), r));
} else {
entity->p = new_player_p;
}
#else
unsigned int min_tile_x = 0;
unsigned int min_tile_y = 0;
unsigned int one_past_max_tile_x = 0;
unsigned int one_past_max_tile_y = 0;
unsigned int abs_tile_z = game_state->player_p.abs_tile_z;
tile_map_position best_player_p = game_state->player_p;
F32 best_distance = length_sq(player_delta);
for(unsigned int abs_tile_y = min_tile_y;
abs_tile_y != one_past_max_tile_y;
abs_tile_y++)
{
for(unsigned int abs_tile_x = min_tile_x;
abs_tile_x != one_past_max_tile_x;
abs_tile_x++)
{
tile_map_position test_tile_p =
centered_tile_point(abs_tile_x, abs_tile_y, abs_tile_z);
unsigned int tile_value =
get_tile_value_by_pos(tile_map, test_tile_p);
if(is_tile_value_empty(tile_value)) {
v2 min_corner = v2_multiply(-0.5f,
(v2){ tile_map->tile_side_in_meters,
tile_map->tile_side_in_meters });
v2 max_corner = v2_multiply(-0.5f,
(v2){ tile_map->tile_side_in_meters,
tile_map->tile_side_in_meters });
tile_map_difference rel_new_player_p =
subtract_in_f32(tile_map, &test_tile_p, &new_player_p);
v2 test_p = closest_point_in_rectangle(min_corner,
max_corner,
rel_new_player_p);
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_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 = v2_subtract(Center, TileSide);
Max = v2_add(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.y = entity->height;
draw_rectangle(buffer, player_left_top,
v2_add(player_left_top,
v2_multiply(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;
}
}
*/