A hackable template for creating small and fast browser games.
1import {
2 GL_CLAMP_TO_EDGE,
3 GL_COMPARE_REF_TO_TEXTURE,
4 GL_DATA_FLOAT,
5 GL_DATA_UNSIGNED_BYTE,
6 GL_DATA_UNSIGNED_INT,
7 GL_DEPTH_COMPONENT,
8 GL_DEPTH_COMPONENT24,
9 GL_DEPTH_COMPONENT32F,
10 GL_LINEAR,
11 GL_NEAREST,
12 GL_NEAREST_MIPMAP_LINEAR,
13 GL_PIXEL_UNSIGNED_BYTE,
14 GL_REPEAT,
15 GL_RGBA,
16 GL_RGBA16F,
17 GL_RGBA32F,
18 GL_RGBA8,
19 GL_TEXTURE_2D,
20 GL_TEXTURE_COMPARE_MODE,
21 GL_TEXTURE_MAG_FILTER,
22 GL_TEXTURE_MIN_FILTER,
23 GL_TEXTURE_WRAP_S,
24 GL_TEXTURE_WRAP_T,
25} from "./webgl.js";
26
27export function fetch_image(path: string): Promise<HTMLImageElement> {
28 return new Promise((resolve) => {
29 let image = new Image();
30 image.src = path;
31 image.onload = () => resolve(image);
32 });
33}
34
35export function create_texture_from(gl: WebGLRenderingContext, image: HTMLImageElement) {
36 let texture = gl.createTexture()!;
37 gl.bindTexture(GL_TEXTURE_2D, texture);
38 gl.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, GL_RGBA, GL_PIXEL_UNSIGNED_BYTE, image);
39
40 gl.generateMipmap(GL_TEXTURE_2D);
41
42 if (false) {
43 // The following are the default settings in WebGL2.
44 // GL_TEXTURE_MIN_FILTER: Consider switching to GL_LINEAR_MIPMAP_LINEAR for the best quality.
45 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);
46 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
47 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
48 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
49 }
50
51 return texture;
52}
53
54export interface Spritesheet {
55 Texture: WebGLTexture;
56 Width: number;
57 Height: number;
58}
59
60export function create_spritesheet_from(
61 gl: WebGLRenderingContext,
62 image: HTMLImageElement,
63): Spritesheet {
64 let texture = gl.createTexture()!;
65 gl.bindTexture(GL_TEXTURE_2D, texture);
66 gl.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, GL_RGBA, GL_PIXEL_UNSIGNED_BYTE, image);
67
68 // No mipmapping nor LINEAR scaling to preserve the exact pixel data.
69 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
70 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
71
72 if (false) {
73 // The following are the default settings in WebGL2.
74 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
75 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
76 }
77
78 return {
79 Texture: texture,
80 Width: image.width,
81 Height: image.height,
82 };
83}
84
85export function resize_texture_rgba8(
86 gl: WebGL2RenderingContext,
87 texture: WebGLTexture,
88 width: number,
89 height: number,
90) {
91 gl.bindTexture(GL_TEXTURE_2D, texture);
92 gl.texImage2D(
93 GL_TEXTURE_2D,
94 0,
95 GL_RGBA8,
96 width,
97 height,
98 0,
99 GL_RGBA,
100 GL_DATA_UNSIGNED_BYTE,
101 null,
102 );
103
104 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
105 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
106
107 return texture;
108}
109
110/** Requires EXT_color_buffer_float. */
111export function resize_texture_rgba16f(
112 gl: WebGL2RenderingContext,
113 texture: WebGLTexture,
114 width: number,
115 height: number,
116) {
117 gl.bindTexture(GL_TEXTURE_2D, texture);
118 gl.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, width, height, 0, GL_RGBA, GL_DATA_FLOAT, null);
119
120 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
121 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
122
123 return texture;
124}
125
126/** Requires EXT_color_buffer_float. */
127export function resize_texture_rgba32f(
128 gl: WebGL2RenderingContext,
129 texture: WebGLTexture,
130 width: number,
131 height: number,
132) {
133 gl.bindTexture(GL_TEXTURE_2D, texture);
134 gl.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, width, height, 0, GL_RGBA, GL_DATA_FLOAT, null);
135
136 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
137 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
138
139 return texture;
140}
141
142export function resize_texture_depth24(
143 gl: WebGL2RenderingContext,
144 texture: WebGLTexture,
145 width: number,
146 height: number,
147) {
148 gl.bindTexture(GL_TEXTURE_2D, texture);
149 gl.texImage2D(
150 GL_TEXTURE_2D,
151 0,
152 GL_DEPTH_COMPONENT24,
153 width,
154 height,
155 0,
156 GL_DEPTH_COMPONENT,
157 GL_DATA_UNSIGNED_INT,
158 null,
159 );
160
161 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
162 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
163 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
164 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
165 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
166
167 return texture;
168}
169
170export function resize_texture_depth32f(
171 gl: WebGL2RenderingContext,
172 texture: WebGLTexture,
173 width: number,
174 height: number,
175) {
176 gl.bindTexture(GL_TEXTURE_2D, texture);
177 gl.texImage2D(
178 GL_TEXTURE_2D,
179 0,
180 GL_DEPTH_COMPONENT32F,
181 width,
182 height,
183 0,
184 GL_DEPTH_COMPONENT,
185 GL_DATA_FLOAT,
186 null,
187 );
188
189 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
190 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
191 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
192 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
193 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
194
195 return texture;
196}