Skip to content

Commit 86497b4

Browse files
committed
UI overhaul
1 parent cf98b24 commit 86497b4

10 files changed

Lines changed: 254 additions & 62 deletions

File tree

README.md

-44 Bytes

native-html-images

��

assets/cow.png

73.4 KB
Loading

index.html

Lines changed: 75 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -5,63 +5,105 @@
55
<meta name="viewport" content="width=device-width, initial-scale=1.0">
66
<title>Down with canvas!</title>
77
<script type="module" src="/src/main.ts"></script>
8+
<script>
9+
function toggle_panel(id) {
10+
const el = document.getElementById(id);
11+
el.hidden = !el.hidden;
12+
resize_workspace();
13+
window.dispatchEvent(new Event('resize'));
14+
}
15+
16+
function resize_workspace() {
17+
const svg = document.getElementById('container');
18+
if (svg) {
19+
svg.setAttribute("height", window.innerHeight - 36);
20+
}
21+
}
22+
23+
window.addEventListener('resize', resize_workspace);
24+
window.addEventListener('load', resize_workspace);
25+
</script>
826
</head>
9-
<body bgcolor="grey" text="white">
10-
<center>
11-
<h1><font face="Arial">Down with canvas</font></h1>
12-
13-
<table border="1" cellpadding="10" cellspacing="0" width="900" bgcolor="#111111">
14-
27+
28+
<body topmargin="0" leftmargin="0" marginheight="0" marginwidth="0" bgcolor="#000000" text="white">
29+
30+
<table width="100%" height="35" border="0" cellpadding="0" cellspacing="0" bgcolor="#222222">
1531
<tr>
16-
<td colspan="3" align="right" bgcolor="#222222">
17-
<font face="monospace">Triangles: <b id="poly-count">0</b> / 100000</font>
32+
<td width="300" align="left" valign="middle">
33+
&nbsp;&nbsp;<button onclick="toggle_panel('left-panel')"><b>☰ Create Tools</b></button>
34+
</td>
35+
<td align="center" valign="middle">
36+
<font face="Arial" size="4"><b>Down with canvas</b></font>
37+
&nbsp;&nbsp;
38+
<a href="what.html" target="_blank" style="text-decoration: none;">
39+
<font face="Arial" size="2" color="#aaaaaa">[ What is this? ]</font>
40+
</a>
41+
42+
&nbsp;&nbsp;
43+
<font face="Arial" size="2" color="gray">|</font>
44+
&nbsp;
45+
<font face="Arial" size="2"><b>Wireframe:</b></font>
46+
<input type="checkbox" id="wireframe-mode">
47+
</td>
48+
<td width="300" align="right" valign="middle">
49+
<font face="monospace" size="2" color="#aaaaaa">Triangles: <b id="poly-count"><font color="white">0</font></b> / 100000</font>
50+
&nbsp;&nbsp;&nbsp;
51+
<button onclick="toggle_panel('right-panel')"><b>☰ Inspector</b></button>&nbsp;&nbsp;
1852
</td>
1953
</tr>
54+
</table>
55+
56+
<table width="100%" height="1" border="0" cellpadding="0" cellspacing="0" bgcolor="#333333">
57+
<tr><td></td></tr>
58+
</table>
2059

60+
<table width="100%" border="0" cellpadding="0" cellspacing="0">
2161
<tr valign="top">
2262

23-
<td nowrap width="25%" bgcolor="#1a1a1a">
24-
<h3><font face="Arial">Create</font></h3>
25-
<div id="primitive-toolbar"></div>
26-
<hr>
27-
<div id="primitive-options"></div>
28-
<hr>
63+
<td id="left-panel" width="300" bgcolor="#1a1a1a">
64+
<table width="300" border="0" cellpadding="0" cellspacing="0"><tr><td height="1"></td></tr></table>
65+
66+
<table width="100%" cellpadding="15" cellspacing="0" border="0">
67+
<tr>
68+
<td>
69+
<h3><font face="Arial">Create</font></h3>
70+
<div id="primitive-toolbar"></div>
71+
<hr color="#333333" size="1">
72+
<div id="primitive-options"></div>
73+
</td>
74+
</tr>
75+
</table>
2976
</td>
3077

31-
<td width="50%" align="center" bgcolor="black">
78+
<td align="center" valign="top" bgcolor="black">
3279
<svg
33-
width="800px"
34-
height="600px"
80+
width="100%"
3581
viewBox="-1 -1 2 2"
3682
preserveAspectRatio="none"
37-
stroke-width ="0.01"
83+
stroke-width="0.01"
3884
id="container"
39-
shape-rendering ="optimizeSpeed"
85+
shape-rendering="optimizeSpeed"
4086
>
4187
<path id="render-target" fill="none" stroke="white" stroke-width="0.005" stroke-linejoin="round" />
4288
</svg>
43-
<br><br>
44-
<table border="0" width="100%">
89+
</td>
90+
91+
<td id="right-panel" width="300" bgcolor="#1a1a1a">
92+
<table width="300" border="0" cellpadding="0" cellspacing="0"><tr><td height="1"></td></tr></table>
93+
94+
<table width="100%" cellpadding="15" cellspacing="0" border="0">
4595
<tr>
46-
<td align="center">
47-
<font face="Arial">Wireframe mode?</font> <input type="checkbox" id="wireframe-mode">
96+
<td>
97+
<div id="inspector-panel">
98+
<font color="gray" face="Arial">Select an object to inspect.</font>
99+
</div>
48100
</td>
49101
</tr>
50102
</table>
51103
</td>
52104

53-
<td width="25%" bgcolor="#1a1a1a">
54-
<h3><font face="Arial">Inspector</font></h3>
55-
<div id="inspector-panel">
56-
<font color="gray">Select an object to inspect.</font>
57-
</div>
58-
</td>
59-
60105
</tr>
61106
</table>
62107

63-
<br><br>
64-
65-
</center>
66108
</body>
67109
</html>

src/rendering/process_lighting.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,30 @@ export function process_lighting(mesh:Mesh, scene:Scene, inverse_models:mat4[],
1414
const specular_k = mesh.specular_coefficient;
1515
const shininess = 16;
1616
let index = 0;
17-
17+
1818
for(let i = 0; i < world_coordinates.length; i+=4){
19+
if(mesh.transparent){
20+
mesh.color_buffer[index++] = mesh.albedo[0];
21+
mesh.color_buffer[index++] = mesh.albedo[1];
22+
mesh.color_buffer[index++] = mesh.albedo[2];
23+
continue;
24+
}
1925
vertex[0] = world_coordinates[i];
2026
vertex[1] = world_coordinates[i+1];
2127
vertex[2] = world_coordinates[i+2];
2228
const start = i/4*3;
23-
const nx = mesh.normals[start];
24-
const ny = mesh.normals[start+1];
25-
const nz = mesh.normals[start+2];
2629

30+
let nx = mesh.normals[start];
31+
let ny = mesh.normals[start+1];
32+
let nz = mesh.normals[start+2];
33+
34+
35+
const n_len = Math.sqrt(nx*nx + ny*ny + nz*nz);
36+
if (n_len > 0.00001) {
37+
nx /= n_len;
38+
ny /= n_len;
39+
nz /= n_len;
40+
}
2741

2842
let color = vec3(0,0,0);
2943
for(const light of lights){

src/ui/inspector.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,33 @@ export class Inspector {
9494

9595
this.add_divider(table);
9696

97+
const tr_del = document.createElement("tr");
98+
const td_del = document.createElement("td");
99+
td_del.setAttribute("colspan", "3");
100+
101+
const btn_del = document.createElement("button");
102+
const b_del = document.createElement("b");
103+
const font_del = document.createElement("font");
104+
font_del.setAttribute("color", "red");
105+
font_del.setAttribute("face", "Arial");
106+
font_del.innerText = "Delete Mesh";
107+
b_del.appendChild(font_del);
108+
btn_del.appendChild(b_del);
109+
110+
btn_del.onclick = () => {
111+
node.scale_vec[0] = 0;
112+
node.scale_vec[1] = 0;
113+
node.scale_vec[2] = 0;
114+
node.update_matrix();
115+
this.inspect(node);
116+
};
117+
118+
td_del.appendChild(btn_del);
119+
tr_del.appendChild(td_del);
120+
table.appendChild(tr_del);
121+
122+
this.add_divider(table);
123+
97124
if (node.mesh && node.mesh.albedo && !node.light) {
98125
this.create_color_row(table, "Color", node.mesh.albedo, node.mesh.albedo);
99126
}

src/ui/scene_manager.ts

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,8 @@ export class SceneManager {
101101
else if (type === "Orbit") any_node.animations.push(new Orbit(params[0], params[1], params[2], params[3]));
102102

103103
this.inspector.inspect(this.selected_node);
104-
}
104+
},
105+
() => {this.load_sample_scene()}
105106
);
106107
}
107108

@@ -135,6 +136,32 @@ export class SceneManager {
135136
this.select_node(node);
136137
}
137138

139+
public load_sample_scene() {
140+
const sun_geo = primitives.create_sphere(1.5, 16, 16);
141+
this.add_node(sun_geo, [1.0, 0.8, 0.0]);
142+
const sun = this.nodes[this.nodes.length - 1];
143+
(sun as any).animations = [new Rotator(1, 0.5)];
144+
145+
this.add_point_light(5.0, 50.0, [1.0, 0.9, 0.7], false);
146+
147+
const planet1_geo = primitives.create_sphere(0.5, 12, 12);
148+
this.add_node(planet1_geo, [0.0, 0.5, 1.0]);
149+
const planet1 = this.nodes[this.nodes.length - 1];
150+
(planet1 as any).animations = [new Orbit(1.0, 4.0, 0.0, 0.0), new Rotator(1, 2.0)];
151+
152+
const planet2_geo = primitives.create_3d_ngon(4, 0.8, 0.8);
153+
this.add_node(planet2_geo, [1.0, 0.2, 0.2]);
154+
const planet2 = this.nodes[this.nodes.length - 1];
155+
(planet2 as any).animations = [
156+
new Orbit(0.5, 7.0, 0.0, 0.0),
157+
new Rotator(0, 1.0),
158+
new Rotator(2, 1.0),
159+
new Oscillator(1, 2.0, 1.0, 0.0)
160+
];
161+
162+
alert("Sample scene loaded! Press 'Play' in the Playback menu to see it move.");
163+
}
164+
138165
public add_point_light(intensity: number, radius: number, color_arr: number[] = [1.0, 1.0, 1.0], casts_shadow:boolean) {
139166
const light_color = vec3(color_arr[0], color_arr[1], color_arr[2]);
140167
const new_light = new Light(vec3(0, 0, 0), light_color, intensity, radius,casts_shadow);

src/ui/toolbar.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,8 @@ export function initialize_toolbar(
108108
on_create_geometry: (geo: Geometry, color: number[]) => void,
109109
on_create_light: (intensity: number, radius: number, color: number[], casts_shadow:boolean) => void,
110110
on_playback_action: (action: "play" | "pause" | "stop") => void,
111-
on_add_animation: (type: string, params: number[]) => void
111+
on_add_animation: (type: string, params: number[]) => void,
112+
on_load_sample: () => void
112113
): void {
113114
const toolbar_el = document.getElementById(toolbar_container_id);
114115
const options_el = document.getElementById(options_container_id);
@@ -415,4 +416,19 @@ export function initialize_toolbar(
415416
anim_container.appendChild(btn);
416417
anim_container.appendChild(document.createElement("br"));
417418
});
419+
420+
const samples_container = create_category(toolbar_el, "Samples", false);
421+
422+
const sample_btn = document.createElement("button");
423+
const b_sample = document.createElement("b");
424+
b_sample.innerText = "Load Solar System Scene";
425+
sample_btn.appendChild(b_sample);
426+
427+
sample_btn.addEventListener("click", () => {
428+
options_el.innerHTML = `<h3><font face="Arial">Sample Scene</font></h3><font size="2" color="gray">Loading the animated sample scene...</font>`;
429+
on_load_sample();
430+
});
431+
432+
samples_container.appendChild(sample_btn);
433+
samples_container.appendChild(document.createElement("br"));
418434
}

src/ui/viewport.ts

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,16 @@ export class Viewport {
99
public theta: number = Math.PI / 4;
1010
public phi: number = Math.PI / 6;
1111

12-
public projection:mat4 = perspective(60 * Math.PI / 180, 400 / 300, 0.1, 100);
12+
public projection: mat4 = perspective(60 * Math.PI / 180, 400 / 300, 0.1, 100);
1313

1414
private last_mouse_x = 0;
1515
private last_mouse_y = 0;
1616
private is_dragging = false;
1717

18-
private changed_projection = false;
18+
private changed_projection = true;
1919

2020
public container: HTMLElement;
2121

22-
2322
constructor(container_id: string) {
2423
const el = document.getElementById(container_id);
2524
if (!el) throw new Error(`Viewport container '${container_id}' not found.`);
@@ -43,19 +42,18 @@ export class Viewport {
4342
return look_at(this.camera_pos, this.target, vec3(0, 1, 0));
4443
}
4544

46-
public get_dimensions() : {width:number, height:number}{
47-
this.changed_projection = true;
45+
public get_dimensions(): {width: number, height: number} {
4846
return {
4947
width: this.container.clientWidth || 400,
50-
height:this.container.clientHeight || 300
48+
height: this.container.clientHeight || 300
5149
}
5250
}
5351

54-
public get_projection() : mat4 {
55-
if(this.changed_projection){
52+
public get_projection(): mat4 {
53+
if(this.changed_projection) {
5654
const {width, height} = this.get_dimensions();
5755
const ratio = width / height;
58-
this.projection = perspective(60 * Math.PI / 180, ratio, 0.1,100);
56+
this.projection = perspective(60 * Math.PI / 180, ratio, 0.1, 100);
5957
this.changed_projection = false;
6058
}
6159
return this.projection;
@@ -91,5 +89,9 @@ export class Viewport {
9189

9290
this.update_camera_position();
9391
}, { passive: false });
92+
93+
window.addEventListener("resize", () => {
94+
this.changed_projection = true;
95+
});
9496
}
9597
}

src/utils/parser.ts

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import { ArrayType, IndexingType, vec3 } from "../math/types";
22
import { Geometry } from "../rendering/types/geometry";
33

4-
function center_geometry(geo: Geometry): void {
5-
const v = geo.vertices;
4+
function center_geometry(v:ArrayType): void {
65
if (v.length === 0) return;
76

87
let minX = Infinity, minY = Infinity, minZ = Infinity;
@@ -29,20 +28,20 @@ function center_geometry(geo: Geometry): void {
2928
}
3029
}
3130

32-
export function normalize_geometry(geo:Geometry): void {
31+
export function normalize_geometry(v:ArrayType): void {
3332
let max = -Infinity;
34-
for(let i = 0; i < geo.vertices.length; i+=3){
35-
max = Math.max(max,geo.vertices[i])
36-
max = Math.max(max,geo.vertices[i+1])
37-
max = Math.max(max,geo.vertices[i+2])
33+
for(let i = 0; i < v.length; i+=3){
34+
max = Math.max(max,Math.abs(v[i]))
35+
max = Math.max(max,Math.abs(v[i+1]))
36+
max = Math.max(max,Math.abs(v[i+2]))
3837
}
3938
if(max===0){
4039
max = 1;
4140
}
42-
for(let i = 0; i < geo.vertices.length; i+=3){
43-
geo.vertices[i] /= max;
44-
geo.vertices[i+1] /= max;
45-
geo.vertices[i+2] /= max;
41+
for(let i = 0; i < v.length; i+=3){
42+
v[i] /= max;
43+
v[i+1] /= max;
44+
v[i+2] /= max;
4645
}
4746
}
4847

@@ -138,9 +137,8 @@ export function parse_obj(file:string):Geometry{
138137
normals[i + 2] *= len;
139138
}
140139
}
141-
140+
center_geometry(vertices);
141+
normalize_geometry(vertices);
142142
const geo = new Geometry(vertices,indices,normals);
143-
center_geometry(geo);
144-
normalize_geometry(geo);
145143
return geo;
146144
}

0 commit comments

Comments
 (0)