:beer
name="Beer"
texture_path="./assets/images/beer-1.png"
-weight=12.34
[Wall]
id = 10
flags = 2
-pos.x = 168.0000
-pos.y = 320.0000
-size.x = 336.0000
-size.y = 32.0000
+pos.x = 176.0000
+pos.y = 312.0000
+size.x = 352.0000
+size.y = 16.0000
[Wall]
id = 11
flags = 2
-pos.x = 448.0000
-pos.y = 168.0000
-size.x = 32.0000
-size.y = 336.0000
+pos.x = 440.0000
+pos.y = 160.0000
+size.x = 16.0000
+size.y = 320.0000
[Player]
id = 12
flags = 2
-pos.x = 342.9302
-pos.y = 205.3930
-size.x = 48.0000
-size.y = 48.0000
+pos.x = 452.6227
+pos.y = 356.0881
+size.x = 32.0000
+size.y = 32.0000
:PlayerComponent
color.r = 1.0000
color.g = 1.0000
controls.right = 68
controls.interact = 70
controls.pick_up = 71
-facing = 4
+facing = 1
[Door]
id = 13
flags = 3
pos.x = 352.0000
-pos.y = 320.0000
+pos.y = 312.0000
size.x = 160.0000
-size.y = 32.0000
+size.y = 16.0000
:DoorComponent
max_openness = 0.8000
-target_openness = 0.0000
-openness = 0.0000
+target_openness = 0.8000
+openness = 0.8000
[Item_Entity]
id = 14
flags = 4
-pos.x = 386.9302
-pos.y = 205.3930
-size.x = 32.0000
-size.y = 32.0000
+pos.x = 508.3851
+pos.y = 375.2260
+size.x = 16.0000
+size.y = 16.0000
:ItemComponent
item = "beer"
#load "entity/player"
#load "entity/store"
+#load "gfx/canvas"
#load "gfx/font"
#load "gfx/immediate"
#load "gfx/mesh"
Editor_Range :: struct {min, max: f32;}
Editor_Disabled :: struct {}
+Editor_Hidden :: struct {}
Editor_Custom_Field :: struct { func: () -> void; }
editor_init :: () {
}
editor_shown :: () => editor_openness != 0.0f || editor_target_openness != 0.0f;
+editor_open_percent :: () => editor_openness;
editor_toggle :: () {
editor_target_openness = 1.0f - editor_target_openness;
#local handle_placing_entities :: () {
if active_index < 0 do return;
- mouse_pos := mouse_get_position_vector();
+ mouse_pos := mouse_get_position_vector() - scene_render_offset;
if is_button_just_down(GLFW_MOUSE_BUTTON_LEFT) && mouse_pos.x < ~~window_width - sidebar_width && mouse_pos.y > menubar_height {
schematic := scene.schematics.entries[active_index].value;
}
#local handle_entity_selction_and_dragging :: (dt: f32) {
- mouse_pos := mouse_get_position_vector();
+ mouse_pos := mouse_get_position_vector() - scene_render_offset;
if mouse_pos.x < ~~window_width - sidebar_width && mouse_pos.y > menubar_height {
if is_button_just_down(GLFW_MOUSE_BUTTON_LEFT) || is_button_just_down(GLFW_MOUSE_BUTTON_RIGHT) {
if dragging {
if editor_grid_shown {
- new_top_left := mouse_get_position_vector();
+ new_top_left := mouse_get_position_vector() - scene_render_offset;
new_top_left.x = editor_grid_size * math.floor(new_top_left.x / editor_grid_size);
new_top_left.y = editor_grid_size * math.floor(new_top_left.y / editor_grid_size);
if resizing {
if editor_grid_shown {
rect := Entity.get_rect(selected_entity);
- new_size := mouse_get_position_vector() - Rect.top_left(rect);
+ new_size := mouse_get_position_vector() - Rect.top_left(rect) - scene_render_offset;
new_size.x = editor_grid_size * math.floor(new_size.x / editor_grid_size);
new_size.y = editor_grid_size * math.floor(new_size.y / editor_grid_size);
new_rect := Rect.{ rect.x, rect.y, new_size.x, new_size.y };
editor_draw :: () {
if editor_grid_shown {
- width := cast(f32) window_width;
- height := cast(f32) window_height;
+ width := cast(f32) scene_canvas.width;
+ height := cast(f32) scene_canvas.height;
xcount := cast(i32) math.ceil(height / editor_grid_size);
ycount := cast(i32) math.ceil(width / editor_grid_size);
immediate_set_color(.{1,1,0});
for xcount {
- y := ~~it * editor_grid_size;
- immediate_line(0, y, width, y);
+ y := ~~it * editor_grid_size + scene_render_offset.y;
+ immediate_line(scene_render_offset.x, y, width + scene_render_offset.x, y);
}
for ycount {
- x := ~~it * editor_grid_size;
- immediate_line(x, 0, x, height);
+ x := ~~it * editor_grid_size + scene_render_offset.x;
+ immediate_line(x, scene_render_offset.y, x, height + scene_render_offset.y);
}
}
- scene->draw();
immediate_flush();
if selected_entity_id != Entity_Nothing {
selected_entity := scene->get(selected_entity_id);
r := Entity.get_rect(selected_entity);
+ r.x += scene_render_offset.x;
+ r.y += scene_render_offset.y;
immediate_set_color(.{1,1,0,0.5});
immediate_rectangle(r.x-2, r.y-2, r.w+4, r.h+4);
immediate_rectangle(r.x, r.y, r.w, r.h);
info := cast(^type_info.Type_Info_Struct) type_info.get_type_info(v.type);
for^ info.members {
+ for^ it.tags {
+ if it.type != type_expr do continue;
+ if *cast(^type_expr) it.data == Editor_Hidden do continue continue;
+ }
+
i += 1;
y += Field_Height;
Item :: struct {
name: str;
- weight := 10.0f;
color := Color.{ 1, 1, 1 };
texture_path : str;
return items[id];
}
-#local Item_Entity :: struct [Entity_Schematic.{create}] {
+#local Item_Entity :: struct {
+ #struct_tag Entity_Schematic.{create}
+
create :: (scene) => {
this := scene->make();
this.pos = .{0, 0};
ItemComponent :: struct {
use base: Component;
- [Editor_Custom_Field.{render_item_picker}]
+ #tag Editor_Custom_Field.{render_item_picker}
item: str;
}
}
Component :: struct {
- [Entity_Store.Skip] use vtable: ^Component_Vtable;
- [Entity_Store.Skip] type: type_expr;
+ #tag Editor_Hidden, Entity_Store.Skip
+ use vtable: ^Component_Vtable;
+
+ #tag Editor_Hidden, Entity_Store.Skip
+ type: type_expr;
}
IsComponent :: interface (c: $C) {
RenderComponent :: struct {
use base: Component;
func : (e: ^Entity) -> void;
+
+ #struct_tag Entity_Store.Skip
}
-SizeComponent :: struct [Entity_Store.Skip] {
+SizeComponent :: struct {
use base: Component;
func : (e: ^Entity) -> Rect;
+
+ #struct_tag Entity_Store.Skip
}
-InteractableComponent :: struct [Entity_Store.Skip] {
+InteractableComponent :: struct {
use base: Component;
interact: (e: ^Entity, interactor: ^Entity) -> void;
+
+ #struct_tag Entity_Store.Skip
}
Entity :: struct {
id: Entity_ID;
flags: Entity_Flags;
- [Entity_Store.Skip] schematic: type_expr;
+ #tag Entity_Store.Skip
+ schematic: type_expr;
pos: Vector2;
return Rect.{ pos.x - size.x / 2, pos.y - size.y / 2, size.x, size.y };
};
- [Entity_Store.Skip]
+ #tag Entity_Store.Skip
components: Map(type_expr, ^Component);
+
has :: (use this: ^Entity, component_type: type_expr) => components->has(component_type);
get :: (use this: ^Entity, $component_type: type_expr) => cast(^component_type) components[component_type];
add :: (use this: ^Entity, component: ^Component) => {
}
}
-#local Player :: struct [Entity_Schematic.{create}] {
+#local Player :: struct {
+ #struct_tag Entity_Schematic.{create}
create :: (scene: ^Entity_Manager) => player_create(scene, .{0,0});
}
}
}
-#local Wall :: struct [Entity_Schematic.{create}] {
- create :: (scene) => wall_create(scene, .{0,0}, .{0,0});
-
- draw :: (use this: ^Entity) {
+#local Wall :: struct {
+ render :: (use this: ^Entity) {
immediate_set_color(.{1,1,1});
r := Entity.get_rect(this);
immediate_rectangle(r.x, r.y, r.w, r.h);
}
+
+ #struct_tag Entity_Schematic.{
+ (scene) => wall_create(scene, .{0,0}, .{0,0})
+ }
}
wall_create :: (scene: ^Entity_Manager, pos, size: Vector2) -> ^Entity {
this.flags |= .Solid;
scene->create_and_add(this, RenderComponent) {
- comp.func = Wall.draw;
+ comp.func = Wall.render;
}
return this;
}
player_assets: struct {
- ["assets/images/player.png"] texture: Texture;
+ #tag "assets/images/player.png"
+ texture: Texture;
}
-#local Door :: struct [Entity_Schematic.{create}] {
- create :: (scene) => door_create(scene, .{0, 0}, .{0, 0});
+#local Door :: struct {
+ create :: (scene) => door_create(scene, .Zero, .Zero);
render :: (use this: ^Entity) {
immediate_set_color(.{0.7, 0.7, 0.1});
door->toggle_open();
}
}
+
+ #struct_tag Entity_Schematic.{create}
}
DoorComponent :: struct {
use package core
use package glfw3
+use package opengles
//
// Game Global Variables
scene: Entity_Manager;
item_store: Item_Store;
+scene_render_offset: Vector2;
+scene_canvas: Canvas;
+
game_init :: () {
+ scene_canvas = canvas_make(800, 600);
+
// This process of queueing the asset bucket should
// be made automatic somehow...
queue_assets(^player_assets);
}
game_draw :: () {
+ canvas_use(^scene_canvas);
+ immediate_clear(.{0.15, 0.15, 0.2});
+ scene->draw();
+ immediate_flush();
+ canvas_use(null);
+
+ immediate_clear(.{0, 0, 0});
+
+ texture := canvas_to_texture(^scene_canvas);
+ view_rect: Rect;
+ view_rect.x = math.lerp(editor_open_percent(), cast(f32) ((window_width - scene_canvas.width) / 2), 0);
+ view_rect.y = ~~ ((window_height - scene_canvas.height) / 2);
+ view_rect.w = ~~ scene_canvas.width;
+ view_rect.h = ~~ scene_canvas.height;
+ scene_render_offset = Rect.top_left(view_rect);
+
+ glDisable(GL_CULL_FACE);
+ immediate_image(^texture, view_rect.x, ~~window_height - view_rect.y, view_rect.w, -view_rect.h);
+ immediate_flush();
+ glEnable(GL_CULL_FACE);
+
update_world_matrix();
update_model_matrix(.{0,0});
return;
}
- scene->draw();
}
Canvas :: struct {
+ width, height: i32;
+
framebuffer: GLint;
depth_stencil_buffer: GLint;
color_texture: GLint;
}
-canvas_make :: () -> Canvas {
+canvas_make :: (width, height: i32) -> Canvas {
canvas: Canvas;
+ canvas.width = width;
+ canvas.height = height;
+
+ glGenFramebuffers(1, ^canvas.framebuffer);
+ glBindFramebuffer(GL_FRAMEBUFFER, canvas.framebuffer);
+
+ glGenTextures(1, ^canvas.color_texture);
+ glBindTexture(GL_TEXTURE_2D, canvas.color_texture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, null);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, canvas.color_texture, 0);
+
+ glGenRenderbuffers(1, ^canvas.depth_stencil_buffer);
+ glBindRenderbuffer(GL_RENDERBUFFER, canvas.depth_stencil_buffer);
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
+ glBindRenderbuffer(GL_RENDERBUFFER, 0);
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, canvas.depth_stencil_buffer);
+
+ if glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE {
+ debug_log(.Error, "Framebuffer is not complete!");
+ }
+
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ return canvas;
+}
+
+canvas_free :: (use canvas: ^Canvas) {
+ glDeleteFramebuffers(1, ^canvas.framebuffer);
+ glDeleteTextures(1, ^canvas.color_texture);
+ glDeleteRenderbuffers(1, ^canvas.depth_stencil_buffer);
}
canvas_use :: (use canvas: ^Canvas) {
if canvas == null {
glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ update_view_matrix(window_width, window_height);
} else {
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
+ update_view_matrix(width, height);
}
}
+canvas_to_texture :: (canvas: ^Canvas) => Texture.{ canvas.color_texture, canvas.width, canvas.height, 3, "<canvas>" };
}
}
-update_view_matrix :: () {
+update_view_matrix :: (width, height: u32) {
matrix : [16] f32;
top := 0.0f;
left := 0.0f;
- right := cast(f32) window_width;
- bottom := cast(f32) window_height;
+ right := cast(f32) width;
+ bottom := cast(f32) height;
far := 10.0f;
near := 0f;
glBindBuffer(GL_UNIFORM_BUFFER, window_matrix_block_buffer);
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof typeof matrix, ^matrix);
glBindBuffer(GL_UNIFORM_BUFFER, -1);
+
+ glViewport(0, 0, width, height);
}
update_world_matrix :: () {
game_init();
glfwGetWindowSize(window, ^window_width, ^window_height);
- glViewport(0, 0, window_width, window_height);
- update_view_matrix();
+ update_view_matrix(window_width, window_height);
#if DEBUG { debug_font = font_lookup(.{"./assets/fonts/calibri.ttf", 16}); }
}
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
}
- window := glfwCreateWindow(800, 600, #cstr "Bar simulator");
+ window := glfwCreateWindow(1200, 900, #cstr "Bar simulator");
glfwMakeContextCurrent(window);
glfwSwapInterval(1);
}
#export "on_resize" (window: GLFWwindow_p, width, height: u32) {
- glViewport(0, 0, width, height);
window_width = width;
window_height = height;
- update_view_matrix();
+ update_view_matrix(width, height);
}
main :: (args) => {
-Vector2 :: struct [conv.Custom_Format.{format_vector2}] {
+Vector2 :: struct {
x, y: f32;
mag :: macro (v: Vector2) => math.sqrt(v.x * v.x + v.y * v.y);
+ Zero :: Vector2.{0, 0}
+
+ #struct_tag conv.Custom_Format.{format_vector2}
}
-Vector3i :: struct [conv.Custom_Format.{format_vector3i}] {
+Vector3i :: struct {
x, y, z: i32;
+ #struct_tag conv.Custom_Format.{format_vector3i}
}
-Vector3 :: struct [conv.Custom_Format.{format_vector3}] {
+Vector3 :: struct {
x, y, z: f32;
mag :: macro (v: Vector3) => math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
math.clamp(v.z, min.z, max.z),
};
}
+
+ #struct_tag conv.Custom_Format.{format_vector3}
}
#operator + macro (v1, v2: Vector2) => (typeof v1).{ v1.x + v2.x, v1.y + v2.y };