Archived
Initial commit, with a basic window and GLArea
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
/* application.vala
|
||||
*
|
||||
* Copyright 2026 Brody Brooks
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
public class Worldbuilder.Application : Adw.Application {
|
||||
|
||||
public Application () {
|
||||
Object (
|
||||
application_id: "com.brodybrooks.WorldBuilder",
|
||||
flags: ApplicationFlags.DEFAULT_FLAGS,
|
||||
resource_base_path: "/com/brodybrooks/WorldBuilder"
|
||||
);
|
||||
}
|
||||
|
||||
construct {
|
||||
ActionEntry[] action_entries = {
|
||||
{ "about", this.on_about_action },
|
||||
{ "preferences", this.on_preferences_action },
|
||||
{ "quit", this.quit }
|
||||
};
|
||||
this.add_action_entries (action_entries, this);
|
||||
this.set_accels_for_action ("app.quit", {"<control>q"});
|
||||
}
|
||||
|
||||
public override void activate () {
|
||||
base.activate ();
|
||||
var win = this.active_window ?? new Worldbuilder.Window (this);
|
||||
win.present ();
|
||||
}
|
||||
|
||||
private void on_about_action () {
|
||||
string[] developers = { "Brody Brooks" };
|
||||
var about = new Adw.AboutDialog () {
|
||||
application_name = "WorldBuilder",
|
||||
application_icon = "com.brodybrooks.WorldBuilder",
|
||||
developer_name = "Brody Brooks",
|
||||
translator_credits = _("translator-credits"),
|
||||
version = "0.1.0",
|
||||
developers = developers,
|
||||
copyright = "© 2026 Brody Brooks",
|
||||
};
|
||||
|
||||
about.present (this.active_window);
|
||||
}
|
||||
|
||||
private void on_preferences_action () {
|
||||
message ("app.preferences action activated");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
[CCode (cprefix = "", lower_case_cprefix = "", cheader_filename = "config.h")]
|
||||
namespace Config {
|
||||
public const string GETTEXT_PACKAGE;
|
||||
public const string LOCALEDIR;
|
||||
public const string PACKAGE_VERSION;
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
/**
|
||||
* A 4-by-4 matrix useful in OpenGL matrix operations.
|
||||
*/
|
||||
public struct Ch3.Mat4x4 {
|
||||
public float data[4*4];
|
||||
|
||||
/**
|
||||
* Create a new matrix with a value along its diagonal.
|
||||
*/
|
||||
public Mat4x4 (float diagonal_value) {
|
||||
for (int i = 0; i < 4; i++)
|
||||
this[i, i] = diagonal_value;
|
||||
}
|
||||
|
||||
public Mat4x4.identity () {
|
||||
this (1.0f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a perspective transform.
|
||||
*
|
||||
* @param fov field of view, angle in radians
|
||||
* @param aspect_ratio width / height
|
||||
* @param near distance to near plane along the z axis
|
||||
* @param far distance to far plane along the z axis
|
||||
*/
|
||||
public Mat4x4.perspective (float fov, float aspect_ratio, float near, float far) {
|
||||
// see http://www.songho.ca/opengl/gl_projectionmatrix.html
|
||||
|
||||
float height_2 = Math.tanf (fov / 2) * near;
|
||||
float width_2 = aspect_ratio * height_2;
|
||||
|
||||
this[0, 0] = near / width_2;
|
||||
|
||||
this[1, 1] = near / height_2;
|
||||
|
||||
this[2, 2] = -(far + near) / (far - near);
|
||||
this[2, 3] = -2 * far * near / (far - near);
|
||||
|
||||
this[3, 2] = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a transformation matrix for a camera looking at `target` from
|
||||
* `position`.
|
||||
*
|
||||
* @param position the position of the camera
|
||||
* @param target what the camera is looking at
|
||||
* @param up a direction that represents "up"
|
||||
*/
|
||||
public Mat4x4.look_at (Vec3 position, Vec3 target, Vec3 up) {
|
||||
// see https://learnopengl.com/Getting-started/Camera
|
||||
|
||||
up = up.normalized ();
|
||||
var direction = position.subtract (target).normalized ();
|
||||
var right = up.cross (direction).normalized ();
|
||||
up = direction.cross (right).normalized ();
|
||||
|
||||
this[0, 0] = right.x;
|
||||
this[0, 1] = right.y;
|
||||
this[0, 2] = right.z;
|
||||
this[0, 3] = right.x * (-position.x) + right.y + (-position.y) + right.z * (-position.z);
|
||||
|
||||
this[1, 0] = up.x;
|
||||
this[1, 1] = up.y;
|
||||
this[1, 2] = up.z;
|
||||
this[1, 3] = up.x * (-position.x) + up.y * (-position.y) + up.z * (-position.z);
|
||||
|
||||
this[2, 0] = direction.x;
|
||||
this[2, 1] = direction.y;
|
||||
this[2, 2] = direction.z;
|
||||
this[2, 3] = direction.x * (-position.x) + direction.y * (-position.y) + direction.z * (-position.z);
|
||||
|
||||
this[3, 3] = 1;
|
||||
}
|
||||
|
||||
public void set (int row, int col, float value) {
|
||||
data[col*4 + row] = value;
|
||||
}
|
||||
|
||||
public float get (int row, int col) {
|
||||
return data[col*4 + row];
|
||||
}
|
||||
|
||||
public Mat4x4 write (int row, int col, float value) {
|
||||
var copy = this;
|
||||
copy[row, col] = value;
|
||||
return copy;
|
||||
}
|
||||
|
||||
public Mat4x4 rotateX (float radians) {
|
||||
// see https://learnopengl.com/Getting-started/Transformations
|
||||
var copy = this;
|
||||
// rotate around x axis
|
||||
float sin_x, cos_x;
|
||||
Math.sincosf (radians, out sin_x, out cos_x);
|
||||
for (int col = 0; col < 4; col++) {
|
||||
// copy[0, col] = this[0, col];
|
||||
copy[1, col] = cos_x * this[1, col] - sin_x * this[2, col];
|
||||
copy[2, col] = sin_x * this[1, col] + cos_x * this[2, col];
|
||||
// copy[3, col] = this[3, col];
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
public Mat4x4 rotateY (float radians) {
|
||||
var copy = this;
|
||||
// rotate around y axis
|
||||
float sin_y, cos_y;
|
||||
Math.sincosf (radians, out sin_y, out cos_y);
|
||||
for (int col = 0; col < 4; col++) {
|
||||
copy[0, col] = cos_y * this[0, col] + sin_y * this[2, col];
|
||||
// copy[1, col] = this[1, col];
|
||||
copy[2, col] = -sin_y * this[0, col] + cos_y * this[2, col];
|
||||
// copy[3, col] = this[3, col];
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
public Mat4x4 rotateZ (float radians) {
|
||||
var copy = this;
|
||||
// rotate around z axis
|
||||
float sin_z, cos_z;
|
||||
Math.sincosf (radians, out sin_z, out cos_z);
|
||||
for (int col = 0; col < 4; col++) {
|
||||
copy[0, col] = cos_z * this[0, col] - sin_z * this[1, col];
|
||||
copy[1, col] = sin_z * this[0, col] + cos_z * this[1, col];
|
||||
// copy[2, col] = this[2, col];
|
||||
// copy[3, col] = this[3, col];
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
public Mat4x4 scale (float x, float y, float z) {
|
||||
var copy = this;
|
||||
copy[0, 0] *= x;
|
||||
copy[1, 1] *= y;
|
||||
copy[2, 2] *= z;
|
||||
return copy;
|
||||
}
|
||||
|
||||
public Mat4x4 translate (float x, float y, float z) {
|
||||
var copy = this;
|
||||
copy[0, 3] += x;
|
||||
copy[1, 3] += y;
|
||||
copy[2, 3] += z;
|
||||
return copy;
|
||||
}
|
||||
|
||||
public Mat4x4 multiply (Mat4x4 other) {
|
||||
var result = Mat4x4 (0);
|
||||
|
||||
// this x other = result
|
||||
for (int row = 0; row < 4; row++)
|
||||
for (int col = 0; col < 4; col++)
|
||||
for (int k = 0; k < 4; k++) // FIXME: codegen with result[row, col] += ... versus = ... + ...
|
||||
result[row, col] = result[row, col] + this[row, k] * other[k, col];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public string to_string (string format = "%f") {
|
||||
string vals[4*4];
|
||||
int maxlen = 0;
|
||||
|
||||
for (int row = 0; row < 4; row++) {
|
||||
for (int col = 0; col < 4; col++) {
|
||||
vals[col*4 + row] = this[row, col].to_string (format);
|
||||
var len = vals[col*4 + row].length;
|
||||
if (len > maxlen)
|
||||
maxlen = len;
|
||||
}
|
||||
}
|
||||
|
||||
var sb = new StringBuilder ();
|
||||
for (int row = 0; row < 4; row++) {
|
||||
sb.append ("| ");
|
||||
for (int col = 0; col < 4; col++) {
|
||||
var len = vals[col*4 + row].length;
|
||||
sb.append (vals[col*4 + row]);
|
||||
for (int i = 0; i < maxlen - len; i++)
|
||||
sb.append_c (' ');
|
||||
if (col < 3)
|
||||
sb.append_c (' ');
|
||||
}
|
||||
sb.append (" |\n");
|
||||
}
|
||||
return sb.str;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
public struct Worldbuilder.Vector2 {
|
||||
public float x;
|
||||
public float y;
|
||||
|
||||
public Vec2 (float x = 0, float y = 0) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public string to_string () {
|
||||
return @"<$x,$y>";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
public struct Worldbuilder.Vector3 {
|
||||
public float x;
|
||||
public float y;
|
||||
public float z;
|
||||
|
||||
public Vector3 (float x = 0, float y = 0, float z = 0)
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
public Vector3 normalized ()
|
||||
requires (length >= 1e-9)
|
||||
{
|
||||
return Vector3 (x/length, y/length, z/length);
|
||||
}
|
||||
|
||||
public float length
|
||||
{
|
||||
get { return Math.sqrtf (x*x + y*y + z*z); }
|
||||
}
|
||||
|
||||
public Vector3 add (Vector3 other)
|
||||
{
|
||||
return Vector3 (x + other.x, y + other.y, z + other.z);
|
||||
}
|
||||
|
||||
public Vector3 subtract (Vector3 other)
|
||||
{
|
||||
return Vector3 (x - other.x, y - other.y, z - other.z);
|
||||
}
|
||||
|
||||
public Vector3 cross (Vector3 other)
|
||||
{
|
||||
return Vector3 (y * other.z - z * other.y, -(x * other.z - z * other.x), x * other.y - y * other.x);
|
||||
}
|
||||
|
||||
public string to_string ()
|
||||
{
|
||||
return @"<$x,$y,$z>";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
/* main.vala
|
||||
*
|
||||
* Copyright 2026 Brody Brooks
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
int main (string[] args) {
|
||||
Intl.bindtextdomain (Config.GETTEXT_PACKAGE, Config.LOCALEDIR);
|
||||
Intl.bind_textdomain_codeset (Config.GETTEXT_PACKAGE, "UTF-8");
|
||||
Intl.textdomain (Config.GETTEXT_PACKAGE);
|
||||
|
||||
var app = new Worldbuilder.Application ();
|
||||
return app.run (args);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
worldbuilder_sources = [
|
||||
'main.vala',
|
||||
'application.vala',
|
||||
'window.vala',
|
||||
]
|
||||
|
||||
worldbuilder_deps = [
|
||||
config_dep,
|
||||
dependency('gtk4', version: '>= 4.2'),
|
||||
dependency('libadwaita-1', version: '>= 1.4'),
|
||||
cc.find_library('epoxy'),
|
||||
valac.find_library('gl', dirs: meson.source_root() / 'vapi'),
|
||||
]
|
||||
|
||||
worldbuilder_sources += gnome.compile_resources('worldbuilder-resources',
|
||||
'worldbuilder.gresource.xml',
|
||||
c_name: 'worldbuilder'
|
||||
)
|
||||
|
||||
executable('worldbuilder', worldbuilder_sources,
|
||||
dependencies: worldbuilder_deps,
|
||||
include_directories: config_inc,
|
||||
install: true,
|
||||
)
|
||||
@@ -0,0 +1,5 @@
|
||||
|
||||
public class Worldbuilder.SceneRenderer : Object
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<object class="AdwShortcutsDialog" id="shortcuts_dialog">
|
||||
<child>
|
||||
<object class="AdwShortcutsSection">
|
||||
<property name="title" translatable="yes">Shortcuts</property>
|
||||
<child>
|
||||
<object class="AdwShortcutsItem">
|
||||
<property name="title" translatable="yes" context="shortcut window">Show Shortcuts</property>
|
||||
<property name="action-name">app.shortcuts</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwShortcutsItem">
|
||||
<property name="title" translatable="yes" context="shortcut window">Quit</property>
|
||||
<property name="action-name">app.quit</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
@@ -0,0 +1,54 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<requires lib="gtk" version="4.0"/>
|
||||
<requires lib="Adw" version="1.0"/>
|
||||
<template class="WorldbuilderWindow" parent="AdwApplicationWindow">
|
||||
<property name="title" translatable="yes">WorldBuilder</property>
|
||||
<style>
|
||||
<class name="devel"/>
|
||||
</style>
|
||||
<property name="default-width">800</property>
|
||||
<property name="default-height">600</property>
|
||||
<property name="content">
|
||||
<object class="AdwToolbarView">
|
||||
|
||||
<child type="top">
|
||||
<object class="AdwHeaderBar">
|
||||
<child type="end">
|
||||
<object class="GtkMenuButton">
|
||||
<property name="primary">True</property>
|
||||
<property name="icon-name">open-menu-symbolic</property>
|
||||
<property name="tooltip-text" translatable="yes">Main Menu</property>
|
||||
<property name="menu-model">primary_menu</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<property name="content">
|
||||
<object class="GtkGLArea" id="draw_area">
|
||||
<property name="hexpand">true</property>
|
||||
<property name="vexpand">true</property>
|
||||
</object>
|
||||
</property>
|
||||
|
||||
</object>
|
||||
</property>
|
||||
</template>
|
||||
<menu id="primary_menu">
|
||||
<section>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">_Preferences</attribute>
|
||||
<attribute name="action">app.preferences</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">_Keyboard Shortcuts</attribute>
|
||||
<attribute name="action">app.shortcuts</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">_About WorldBuilder</attribute>
|
||||
<attribute name="action">app.about</attribute>
|
||||
</item>
|
||||
</section>
|
||||
</menu>
|
||||
</interface>
|
||||
@@ -0,0 +1,40 @@
|
||||
/* window.vala
|
||||
*
|
||||
* Copyright 2026 Brody Brooks
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
[GtkTemplate (ui = "/com/brodybrooks/WorldBuilder/window.ui")]
|
||||
public class Worldbuilder.Window : Adw.ApplicationWindow {
|
||||
[GtkChild]
|
||||
private unowned Gtk.GLArea draw_area;
|
||||
|
||||
public Window (Gtk.Application app) {
|
||||
Object (application: app);
|
||||
|
||||
draw_area.render.connect(Render);
|
||||
}
|
||||
|
||||
private bool Render (Gtk.GLArea area, Gdk.GLContext context)
|
||||
{
|
||||
// set the background color
|
||||
GL.glClearColor (0.1f, 0.2f, 0.4f, 1.0f);
|
||||
GL.glClear(GL.GL_COLOR_BUFFER_BIT);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<gresources>
|
||||
<gresource prefix="/com/brodybrooks/WorldBuilder">
|
||||
<file preprocess="xml-stripblanks">window.ui</file>
|
||||
<file preprocess="xml-stripblanks">shortcuts-dialog.ui</file>
|
||||
</gresource>
|
||||
</gresources>
|
||||
Reference in New Issue
Block a user