Skip to content

Commit 6ee55b8

Browse files
authored
fix: type safety for WebGL constants and preliminary blend mode (#61)
1 parent baf3387 commit 6ee55b8

File tree

6 files changed

+88
-99
lines changed

6 files changed

+88
-99
lines changed

src/gfx/apis/webgl2/WebGL2Device.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,19 @@ import Device from '../../Device';
22
import ShaderRegistry from '../../ShaderRegistry';
33
import { ShaderType } from '../../Shader';
44

5-
// import constantsFor from './constants';
6-
5+
import constantsFor from './constants';
76

87
class WebGL2Device extends Device {
98
gl: WebGL2RenderingContext;
109
shaders: ShaderRegistry;
10+
constants;
1111

1212
constructor(canvas: HTMLCanvasElement) {
1313
super();
1414

1515
// TODO: Handle context loss
1616
this.gl = canvas.getContext('webgl2')!;
17-
// TODO: Constants
18-
// this.constants = constantsFor(this.gl);
17+
this.constants = constantsFor(this.gl);
1918

2019
this.shaders = new ShaderRegistry((type, name) => {
2120
const ext = type === 'pixel' ? 'frag' : 'vert';

src/gfx/apis/webgl2/constants.ts

Lines changed: 69 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -5,98 +5,84 @@ import {
55
PrimitiveType,
66
} from '../../types';
77

8-
const cubeMapFaces = {
9-
0: 'TEXTURE_CUBE_MAP_POSITIVE_X',
10-
1: 'TEXTURE_CUBE_MAP_NEGATIVE_X',
11-
2: 'TEXTURE_CUBE_MAP_POSITIVE_Y',
12-
3: 'TEXTURE_CUBE_MAP_NEGATIVE_Y',
13-
4: 'TEXTURE_CUBE_MAP_POSITIVE_Z',
14-
5: 'TEXTURE_CUBE_MAP_NEGATIVE_Z',
15-
} as const;
8+
import { PickByType } from '../../../utils';
169

17-
const blendDestinations = {
18-
[BlendMode.Opaque]: 'ZERO',
19-
[BlendMode.AlphaKey]: 'ZERO',
20-
[BlendMode.Alpha]: 'ONE_MINUS_SRC_ALPHA',
21-
[BlendMode.Add]: 'ONE',
22-
[BlendMode.Mod]: 'ZERO',
23-
[BlendMode.Mod2x]: 'SRC_COLOR',
24-
[BlendMode.ModAdd]: 'ONE',
25-
[BlendMode.InvSrcAlphaAdd]: 'ONE',
26-
[BlendMode.InvSrcAlphaOpaque]: 'ZERO',
27-
[BlendMode.SrcAlphaOpaque]: 'ZERO',
28-
[BlendMode.NoAlphaAdd]: 'ONE',
29-
[BlendMode.ConstantAlpha]: 'ONE_MINUS_CONSTANT_ALPHA',
30-
} as const;
10+
export default (gl: WebGL2RenderingContext) => {
11+
const resolve = (prop: keyof PickByType<WebGL2RenderingContext, number>): number => {
12+
const constant = gl[prop];
13+
if (constant === undefined) {
14+
throw new Error(`Could not find WebGL2 constant: ${prop}`);
15+
}
16+
return constant;
17+
};
3118

32-
const blendSources = {
33-
[BlendMode.Opaque]: 'ONE',
34-
[BlendMode.AlphaKey]: 'ONE',
35-
[BlendMode.Alpha]: 'SRC_ALPHA',
36-
[BlendMode.Add]: 'SRC_ALPHA',
37-
[BlendMode.Mod]: 'DST_COLOR',
38-
[BlendMode.Mod2x]: 'DST_COLOR',
39-
[BlendMode.ModAdd]: 'DST_COLOR',
40-
[BlendMode.InvSrcAlphaAdd]: 'ONE_MINUS_SRC_ALPHA',
41-
[BlendMode.InvSrcAlphaOpaque]: 'ONE_MINUS_SRC_ALPHA',
42-
[BlendMode.SrcAlphaOpaque]: 'SRC_ALPHA',
43-
[BlendMode.NoAlphaAdd]: 'ONE',
44-
[BlendMode.ConstantAlpha]: 'CONSTANT_ALPHA',
45-
} as const;
19+
const constants = {
20+
cubeMapFaces: {
21+
0: resolve('TEXTURE_CUBE_MAP_POSITIVE_X'),
22+
1: resolve('TEXTURE_CUBE_MAP_NEGATIVE_X'),
23+
2: resolve('TEXTURE_CUBE_MAP_POSITIVE_Y'),
24+
3: resolve('TEXTURE_CUBE_MAP_NEGATIVE_Y'),
25+
4: resolve('TEXTURE_CUBE_MAP_POSITIVE_Z'),
26+
5: resolve('TEXTURE_CUBE_MAP_NEGATIVE_Z'),
27+
},
4628

47-
// TODO: Texture format
29+
blendDestinations: {
30+
[BlendMode.Opaque]: resolve('ZERO'),
31+
[BlendMode.AlphaKey]: resolve('ZERO'),
32+
[BlendMode.Alpha]: resolve('ONE_MINUS_SRC_ALPHA'),
33+
[BlendMode.Add]: resolve('ONE'),
34+
[BlendMode.Mod]: resolve('ZERO'),
35+
[BlendMode.Mod2x]: resolve('SRC_COLOR'),
36+
[BlendMode.ModAdd]: resolve('ONE'),
37+
[BlendMode.InvSrcAlphaAdd]: resolve('ONE'),
38+
[BlendMode.InvSrcAlphaOpaque]: resolve('ZERO'),
39+
[BlendMode.SrcAlphaOpaque]: resolve('ZERO'),
40+
[BlendMode.NoAlphaAdd]: resolve('ONE'),
41+
[BlendMode.ConstantAlpha]: resolve('ONE_MINUS_CONSTANT_ALPHA'),
42+
},
4843

49-
const bufferFormatByPoolTarget = {
50-
[PoolTarget.Vertex]: 'ZERO',
51-
[PoolTarget.Index]: 'UNSIGNED_SHORT',
52-
} as const;
44+
blendSources: {
45+
[BlendMode.Opaque]: resolve('ONE'),
46+
[BlendMode.AlphaKey]: resolve('ONE'),
47+
[BlendMode.Alpha]: resolve('SRC_ALPHA'),
48+
[BlendMode.Add]: resolve('SRC_ALPHA'),
49+
[BlendMode.Mod]: resolve('DST_COLOR'),
50+
[BlendMode.Mod2x]: resolve('DST_COLOR'),
51+
[BlendMode.ModAdd]: resolve('DST_COLOR'),
52+
[BlendMode.InvSrcAlphaAdd]: resolve('ONE_MINUS_SRC_ALPHA'),
53+
[BlendMode.InvSrcAlphaOpaque]: resolve('ONE_MINUS_SRC_ALPHA'),
54+
[BlendMode.SrcAlphaOpaque]: resolve('SRC_ALPHA'),
55+
[BlendMode.NoAlphaAdd]: resolve('ONE'),
56+
[BlendMode.ConstantAlpha]: resolve('CONSTANT_ALPHA'),
57+
},
5358

54-
const bufferTypeByPooltarget = {
55-
[PoolTarget.Vertex]: 'ARRAY_BUFFER',
56-
[PoolTarget.Index]: 'ELEMENT_ARRAY_BUFFER',
57-
} as const;
59+
// TODO: Texture format
5860

59-
const bufferUsageByPoolTarget = {
60-
[PoolUsage.Static]: 'STATIC_DRAW',
61-
[PoolUsage.Dynamic]: 'DYNAMIC_DRAW',
62-
[PoolUsage.Stream]: 'DYNAMIC_DRAW',
63-
} as const;
61+
bufferFormatByPoolTarget: {
62+
[PoolTarget.Vertex]: resolve('ZERO'),
63+
[PoolTarget.Index]: resolve('UNSIGNED_SHORT'),
64+
},
6465

65-
const primitiveTypes = {
66-
[PrimitiveType.Points]: 'POINTS',
67-
[PrimitiveType.Lines]: 'LINES',
68-
[PrimitiveType.LineStrip]: 'LINE_STRIP',
69-
[PrimitiveType.Triangles]: 'TRIANGLES',
70-
[PrimitiveType.TriangleStrip]: 'TRIANGLE_STRIP',
71-
[PrimitiveType.TriangleFan]: 'TRIANGLE_FAN',
72-
} as const;
66+
bufferTypeByPooltarget: {
67+
[PoolTarget.Vertex]: resolve('ARRAY_BUFFER'),
68+
[PoolTarget.Index]: resolve('ELEMENT_ARRAY_BUFFER'),
69+
},
7370

74-
export default (gl: WebGL2RenderingContext) => {
75-
const constants = {};
71+
bufferUsageByPoolTarget: {
72+
[PoolUsage.Static]: resolve('STATIC_DRAW'),
73+
[PoolUsage.Dynamic]: resolve('DYNAMIC_DRAW'),
74+
[PoolUsage.Stream]: resolve('DYNAMIC_DRAW'),
75+
},
7676

77-
const categories = {
78-
cubeMapFaces,
79-
blendDestinations,
80-
blendSources,
81-
bufferFormatByPoolTarget,
82-
bufferTypeByPooltarget,
83-
bufferUsageByPoolTarget,
84-
primitiveTypes,
85-
} as const;
86-
87-
for (const [name, category] of Object.entries(categories)) {
88-
const entry = {};
89-
for (const [index, prop] of Object.entries(category)) {
90-
const constant = gl[prop];
91-
if (constant === undefined) {
92-
throw new Error(`Could not find WebGL2 constant: ${prop}`);
93-
}
94-
// @ts-expect-error: currently unused (and untyped)
95-
entry[index] = constant;
96-
}
97-
// @ts-expect-error: currently unused (and untyped)
98-
constants[name] = entry;
99-
}
77+
primitiveTypes: {
78+
[PrimitiveType.Points]: resolve('POINTS'),
79+
[PrimitiveType.Lines]: resolve('LINES'),
80+
[PrimitiveType.LineStrip]: resolve('LINE_STRIP'),
81+
[PrimitiveType.Triangles]: resolve('TRIANGLES'),
82+
[PrimitiveType.TriangleStrip]: resolve('TRIANGLE_STRIP'),
83+
[PrimitiveType.TriangleFan]: resolve('TRIANGLE_FAN'),
84+
},
85+
};
10086

10187
return constants;
10288
};

src/gfx/types.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ export enum BlendMode {
1313
SrcAlphaOpaque = 9,
1414
NoAlphaAdd = 10,
1515
ConstantAlpha = 11,
16-
Last = 12,
1716
}
1817

1918
export enum PoolHintBit {
@@ -26,14 +25,12 @@ export enum PoolHintBit {
2625
export enum PoolTarget {
2726
Vertex = 0,
2827
Index = 1,
29-
Last = 2,
3028
}
3129

3230
export enum PoolUsage {
3331
Static = 0,
3432
Dynamic = 1,
3533
Stream = 2,
36-
Last = 3,
3734
}
3835

3936
export enum PrimitiveType {
@@ -43,7 +40,6 @@ export enum PrimitiveType {
4340
Triangles = 3,
4441
TriangleStrip = 4,
4542
TriangleFan = 5,
46-
Last = 6,
4743
}
4844

4945
export enum RenderStateType {
@@ -133,7 +129,6 @@ export enum RenderStateType {
133129
PointSprite = 83,
134130
Unk84 = 84,
135131
ColorMaterial = 85,
136-
Last = 86,
137132
}
138133

139134
export enum TextureFilter {
@@ -192,5 +187,4 @@ export enum VertexBufferFormat {
192187
PT2 = 11,
193188
PBNT2 = 12,
194189
PNC2T2 = 13,
195-
Last = 14,
196190
}

src/ui/components/abstract/LayoutFrame.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
NDCtoDDCHeight,
1515
NDCtoDDCWidth,
1616
Status,
17+
enumRecordFor,
1718
extractDimensionsFrom,
1819
stringToBoolean,
1920
} from '../../../utils';
@@ -82,11 +83,7 @@ class LayoutFrame {
8283
this.resizeList = LinkedList.using('link');
8384
this.resizeCounter = 0;
8485

85-
this.points = [
86-
null, null, null,
87-
null, null, null,
88-
null, null, null,
89-
];
86+
this.points = enumRecordFor(FramePointType, (_type) => null);
9087
}
9188

9289
// Note: LayoutFrame is used as an auxiliary baseclass using the `multipleClasses` utility, so creating this

src/ui/rendering/Renderer.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class Renderer {
2222

2323
draw(batch: RenderBatch) {
2424
const root = UIRoot.instance;
25-
const { gl } = (Device.instance as WebGL2Device);
25+
const { constants, gl } = (Device.instance as WebGL2Device);
2626
const { pixelShader, vertexShader } = this;
2727

2828
if (!this.program) {
@@ -49,6 +49,14 @@ class Renderer {
4949
for (const mesh of batch.meshes) {
5050
const { image } = mesh.texture;
5151

52+
// TODO: Is this correct?
53+
if (mesh.blendMode) {
54+
gl.enable(gl.BLEND);
55+
gl.blendFunc(constants.blendSources[mesh.blendMode], constants.blendDestinations[mesh.blendMode]);
56+
} else {
57+
gl.disable(gl.BLEND);
58+
}
59+
5260
const texture = gl.createTexture();
5361
gl.activeTexture(gl.TEXTURE0 + 0);
5462
gl.bindTexture(gl.TEXTURE_2D, texture);

src/utils/types.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ export function enumSizeFor<T extends string | number>(enumeration: EnumType<T>)
2525
return enumValuesFor(enumeration).length;
2626
}
2727

28+
// See: https://stackoverflow.com/a/69756175
29+
export type PickByType<T, Value> = {
30+
[P in keyof T as T[P] extends Value | undefined ? P : never]: T[P]
31+
}
32+
2833
// See: https://github.com/microsoft/TypeScript/issues/5863#issuecomment-1336204919
2934
export type ThisConstructor<
3035
T extends { prototype: unknown } = { prototype: unknown },

0 commit comments

Comments
 (0)