I have a working compiler with many features, but here are some additional features
I would like to consider adding in the future.
- [ ] Put type info in data section so it is runtime accessible
+ [X] Put type info in data section so it is runtime accessible
- type name
- size
- alignment
[X] Remove old code from CLI logic
[X] Add statistic printing
- [ ] Fix documentation generation (broken since compiler architecture change)
+ [X] Fix documentation generation (broken since compiler architecture change)
[ ] Add automated running component
- Store to temporary file (OS independent)
- Detect / choose WASM backend
--- /dev/null
+package immediate_mode
+
+use package core
+
+// A render target that can be used instead of the default
+Canvas :: struct {
+ color_texture : Texture;
+ depth_stencil_buffer : gl.GLRenderbuffer;
+ framebuffer : gl.GLFramebuffer;
+
+ width, height: i32;
+}
+
+create_canvas :: (width: i32, height: i32) -> Canvas {
+
+ color_texture := create_texture(width, height, gl.RGBA8);
+
+ depth_stencil_buffer := gl.createRenderbuffer();
+ gl.bindRenderbuffer(gl.RENDERBUFFER, depth_stencil_buffer);
+ gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH24_STENCIL8, width, height);
+ gl.bindRenderbuffer(gl.RENDERBUFFER, -1);
+
+ framebuffer := gl.createFramebuffer();
+ gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, color_texture.texture, 0);
+ gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, depth_stencil_buffer);
+ gl.bindFramebuffer(gl.FRAMEBUFFER, -1);
+
+ assert(gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE, "Framebuffer not complete!");
+
+ return .{
+ color_texture = color_texture,
+ depth_stencil_buffer = depth_stencil_buffer,
+ framebuffer = framebuffer,
+ width = width,
+ height = height,
+ };
+}
+
package immediate_mode
use package core
-#private_file gl :: package gl
+use package core.intrinsics.onyx { __initialize }
Vector2 :: struct {
x, y: f32;
a: f32 = 1;
}
+Immediate_Mode :: enum {
+ Triangles;
+ Lines;
+}
+
Immediate_Vertex :: struct {
position : Vector2;
color : Color4;
}
Immediate_Renderer :: struct {
- // Will point to either the simple_shader or the textured_shader.
active_shader : ^Shader;
simple_shader, textured_shader : Shader;
// 'verticies' contains the vertex data and the maximum number of verticies
// that can be rendered at a given time. 'vertex_count' is used to store how
// many verticies will be rendered in the next draw call. 'vertex_count' is
- // expected to be a multiple of 3, given that triangles are being rendered.
+ // expected to be a multiple of 3 or 2, given that triangles or lines are
+ // being rendered.
verticies : [] Immediate_Vertex;
vertex_count : u32;
vertex_array : gl.GLVertexArrayObject;
vertex_buffer : gl.GLBuffer;
- // Needs to be a multiple of 3!!
- Default_Max_Verticies :: 1023;
+ // Needs to be a multiple of 6!!
+ Default_Max_Verticies :: 1020;
+
+ mode := Immediate_Mode.Triangles;
+
+ canvas: ^Canvas = null;
+
+ window_width, window_height: i32;
make :: (max_verticies := Default_Max_Verticies) -> Immediate_Renderer {
ir : Immediate_Renderer;
+ __initialize(^ir);
init(^ir, max_verticies);
return ir;
gl.bufferSubData(gl.ARRAY_BUFFER, 0, .{ count = vertex_count * sizeof Immediate_Vertex, data = ~~verticies.data });
gl.bindBuffer(gl.ARRAY_BUFFER, -1);
+ gl_mode : gl.GLenum;
+ switch mode {
+ case .Triangles do gl_mode = gl.TRIANGLES;
+ case .Lines do gl_mode = gl.LINES;
+ }
+
gl.useProgram(active_shader.program);
gl.bindVertexArray(vertex_array);
- gl.drawArrays(gl.TRIANGLES, 0, vertex_count);
+ gl.drawArrays(gl_mode, 0, vertex_count);
gl.bindVertexArray(-1);
vertex_count = 0;
gl.disable(gl.SCISSOR_TEST);
}
}
+
+ set_mode :: (use ir: ^Immediate_Renderer, new_mode: Immediate_Mode) {
+ if mode != new_mode {
+ ir->flush();
+ mode = new_mode;
+ }
+ }
+
+ use_canvas :: (use ir: ^Immediate_Renderer, new_canvas: ^Canvas) {
+ if canvas == new_canvas do return;
+ ir->flush();
+
+ canvas = new_canvas;
+ if canvas != null {
+ gl.bindFramebuffer(gl.FRAMEBUFFER, canvas.framebuffer);
+ gl.viewport(0, 0, canvas.width, canvas.height);
+
+ @Note // This flips the projection because generally with using framebuffers as textures,
+ // the bottom left, (0, 0) in WebGL world, you want to be the top left when you render it.
+ ir->use_ortho_projection(0, ~~canvas.width, ~~canvas.height, 0);
+
+ } else {
+ gl.bindFramebuffer(gl.FRAMEBUFFER, -1);
+ gl.viewport(0, 0, window_width, window_height);
+ ir->use_ortho_projection(0, ~~window_width, 0, ~~window_height);
+ }
+ }
+
+ set_window_size :: (use ir: ^Immediate_Renderer, width: i32, height: i32) {
+ window_width = width;
+ window_height = height;
+
+ // If there is no active canvas, immediately update the values.
+ // Maybe this should flush the current buffer first?
+ if canvas == null {
+ gl.viewport(0, 0, window_width, window_height);
+ ir->use_ortho_projection(0, ~~window_width, 0, ~~window_height);
+ }
+ }
}
immediate_renderer : Immediate_Renderer;
immediate_renderer_init :: () {
- Immediate_Renderer.init(^immediate_renderer);
+ immediate_renderer = Immediate_Renderer.make();
}
immediate_renderer_free :: () {
flush :: () do immediate_renderer->flush();
-set_texture :: (texture_id: i32 = -1) do immediate_renderer->set_texture(texture_id);
+set_texture :: #match {
+ (texture_id: i32 = -1) { immediate_renderer->set_texture(texture_id); },
+ (texture: ^Texture, texture_index := 0) {
+ immediate_renderer->set_texture(texture_index);
+
+ if texture_index >= 0 {
+ gl.activeTexture(gl.TEXTURE0 + texture_index);
+ gl.bindTexture(gl.TEXTURE_2D, texture.texture);
+
+ } else {
+ gl.bindTexture(gl.TEXTURE_2D, -1);
+ }
+ }
+}
use_ortho_projection :: (left: f32, right: f32, top: f32, bottom: f32) {
immediate_renderer->use_ortho_projection(left, right, top, bottom);
scissor_disable :: () {
immediate_renderer->scissor_disable();
-}
\ No newline at end of file
+}
+
+set_mode :: (mode: Immediate_Mode) {
+ immediate_renderer->set_mode(mode);
+}
+
+use_canvas :: (canvas: ^Canvas) {
+ immediate_renderer->use_canvas(canvas);
+}
+
+set_window_size :: (width: i32, height: i32) {
+ immediate_renderer->set_window_size(width, height);
+}
#load "./immediate_renderer"
#load "./gl_utils"
+#load "./canvas"
+#load "./texture"
+
+#private gl :: package gl
--- /dev/null
+package immediate_mode
+
+use package core
+
+Texture :: struct {
+ texture : gl.GLTexture;
+
+ width, height: i32;
+}
+
+create_texture :: (width: i32, height: i32, format: gl.GLenum) -> Texture {
+ texture := gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, texture);
+ gl.texStorage2D(gl.TEXTURE_2D, 1, format, width, height);
+
+ // Setting some reasonable defaults for the texture parameters
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+
+ gl.bindTexture(gl.TEXTURE_2D, -1);
+
+ return .{
+ texture = texture,
+ width = width,
+ height = height,
+ };
+}
+
+load_texture :: (width: i32, height: i32, data: [] u8, format: gl.GLenum, internal_type := gl.UNSIGNED_BYTE) -> Texture {
+ texture := gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, texture);
+ gl.texImage2D(gl.TEXTURE_2D, 0, format, width, height, 0, format, internal_type, data);
+
+ // Setting some reasonable defaults for the texture parameters
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+
+ gl.bindTexture(gl.TEXTURE_2D, -1);
+
+ return .{
+ texture = texture,
+ width = width,
+ height = height,
+ };
+}
@Cleanup // Move these to the theme?
// Or create a cache of fonts and put pointers/string in the themes?
#private font : bmfont.BMFont;
-#private font_texture : gl.GLTexture;
+#private font_texture : gfx.Texture;
@Temporary
DEFAULT_TEXT_SIZE :: 1.0f
@FontSizing // Currently, `size` is just a multipler for the baked font size. This should be changed to be height in pixels, or 'em's.
draw_text_raw :: (text: str, x: f32, y: f32, size := DEFAULT_TEXT_SIZE, color := gfx.Color4.{1,1,1}) {
- gl.activeTexture(gl.TEXTURE0);
- gl.bindTexture(gl.TEXTURE_2D, font_texture);
+ gfx.set_texture(^font_texture);
gfx.use_alpha_shader(0);
for glyph: bmfont.get_character_positions(^font, size, text, x, y) {
}
gfx.flush();
- gl.bindTexture(gl.TEXTURE_2D, -1);
+ gfx.set_texture();
}
draw_rect :: #match {
tex_width, tex_height := font.common.scale_width, font.common.scale_height;
- font_texture = gl.createTexture();
- gl.bindTexture(gl.TEXTURE_2D, font_texture);
- gl.texImage2D(gl.TEXTURE_2D, 0, gl.ALPHA, tex_width, tex_height, 0, gl.ALPHA, gl.UNSIGNED_BYTE, texture_data);
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
- gl.bindTexture(gl.TEXTURE_2D, -1);
+ font_texture = gfx.load_texture(tex_width, tex_height, texture_data, gl.ALPHA);
}
gl.bindBuffer(target, buffers[buffer]);
}
},
- bindFramebuffer(target, framebuffer) { gl.bindFramebuffer(target, framebuffers[framebuffer]); },
- bindRenderbuffer(target, renderbuffer) { gl.bindRenderbuffer(target, renderbuffers[renderbuffer]); },
- bindTexture(target, texture) { gl.bindTexture(target, textures[texture]); },
- bindVertexArray(vertexArray) { gl.bindVertexArray(vertexArrays[vertexArray]); },
+ bindFramebuffer(target, framebuffer) {
+ if (framebuffer == -1) {
+ gl.bindFramebuffer(target, null);
+ } else {
+ gl.bindFramebuffer(target, framebuffers[framebuffer]);
+ }
+ },
+ bindRenderbuffer(target, renderbuffer) {
+ if (renderbuffer == -1) {
+ gl.bindRenderbuffer(target, null);
+ } else {
+ gl.bindRenderbuffer(target, renderbuffers[renderbuffer]);
+ }
+ },
+ bindTexture(target, texture) {
+ if (texture == -1) {
+ gl.bindTexture(target, null);
+ } else {
+ gl.bindTexture(target, textures[texture]);
+ }
+ },
+ bindVertexArray(vertexArray) {
+ if (vertexArray == -1) {
+ gl.bindVertexArray(null);
+ } else {
+ gl.bindVertexArray(vertexArrays[vertexArray]);
+ }
+ },
blendColor(red, green, blue, alpha) { gl.blendColor(red, green, blue, alpha); },
blendEquation(mode) { gl.blendEquation(mode); },
canvas.width = width;
canvas.height = height;
},
- checkFrameBufferStatus(target) { return gl.checkFrameBufferStatus(target); },
+ checkFramebufferStatus(target) { return gl.checkFramebufferStatus(target); },
clear(bit) { gl.clear(bit); },
clearColor(r, g, b, a) { gl.clearColor(r, g, b, a); },
clearDepth(depth) { gl.clearDepth(depth); },
gl.compressedSubTexImage2D(target, level, internalformat, xoff, yoff, width, height, format, pixels);
},
copyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, size) { gl.copyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, size); },
- copyTexImage2D(target, level, internalforamt, x, y, width, height, border) {
- gl.copyTexImage2D(target, level, internalforamt, x, y, width, height, border);
+ copyTexImage2D(target, level, internalformat, x, y, width, height, border) {
+ gl.copyTexImage2D(target, level, internalformat, x, y, width, height, border);
},
copyTexSubImage2D(target, level, xoff, yoff, x, y, width, height) {
gl.copyTexSubImage2D(target, level, xoff, yoff, x, y, width, height);
gl.readPixels(x, y, width, height, format, type, pixeldata);
},
readBuffer(src) { gl.readBuffer(src); },
- renderbufferStorageMultisample(target, samples, internalforamt, width, height) {
- gl.renderbufferStorageMultisample(target, samples, internalforamt, width, height);
+ renderbufferStorage(target, internalformat, width, height) { gl.renderbufferStorage(target, internalformat, width, height); },
+ renderbufferStorageMultisample(target, samples, internalformat, width, height) {
+ gl.renderbufferStorageMultisample(target, samples, internalformat, width, height);
},
sampleCoverage(value, invert) { gl.sampleCoverage(value, invert); },
scissor(x, y, width, height) { gl.scissor(x, y, width, height); },
stencilMaskSeparate(face, mask) { gl.stencilMaskSeparate(face, mask); },
stencilOp(fail, zfail, mask) { gl.stencilOp(fail, zfail, mask); },
stencilOpSeparate(face, fail, zfail, zpass) { gl.stencilOpSeparate(face, fail, zfail, zpass); },
- texImage2D(target, level, internalforamt, width, height, border, format, type, pixels, pixelslen) {
+ texImage2D(target, level, internalformat, width, height, border, format, type, pixels, pixelslen) {
const data = new Uint8Array(window.ONYX_MEMORY.buffer, pixels, pixelslen);
- gl.texImage2D(target, level, internalforamt, width, height, border, format, type, data);
+ gl.texImage2D(target, level, internalformat, width, height, border, format, type, data);
},
texParameterf(target, pname, param) { gl.texParameterf(target, pname, param); },
texParameteri(target, pname, param) { gl.texParameteri(target, pname, param); },
+ texStorage2D(target, levels, internalformat, width, height) { gl.texStorage2D(target, levels, internalformat, width, height); },
texSubImage2D(target, level, xoff, yoff, width, height, format, type, pixels, pixelslen) {
const data = new Uint8Array(window.ONYX_MEMORY.buffer, pixels, pixelslen);
gl.texSubImage2D(target, level, xoff, yoff, width, height, format, type, data);
bufferData :: #match { bufferDataWithData, bufferDataNoData }
bufferSubData :: (target: GLenum, offset: GLsizei, data: [] void) -> void #foreign "gl" "bufferSubData" ---
canvasSize :: (width: GLsizei, height: GLsizei) -> void #foreign "gl" "canvasSize" ---
-checkFrameBufferStatus :: (target: GLenum) -> GLenum #foreign "gl" "checkFrameBufferStatus" ---
+checkFramebufferStatus :: (target: GLenum) -> GLenum #foreign "gl" "checkFramebufferStatus" ---
clear :: (mask: GLbitfield) -> void #foreign "gl" "clear" ---
clearColor :: (red: GLclampf, green: GLclampf, blue: GLclampf, alpha: GLclampf) -> void #foreign "gl" "clearColor" ---
clearDepth :: (depth: GLclampf) -> void #foreign "gl" "clearDepth" ---
printShaderInfoLog :: (shader: GLShader) -> void #foreign "gl" "printShaderInfoLog" ---
readBuffer :: (src: GLenum) -> void #foreign "gl" "readBuffer" ---
readPixels :: (x: GLint, y: GLint, width: GLsizei, height: GLsizei, format: GLenum, type: GLenum, pixels: str) -> void #foreign "gl" "readPixels" ---
-renderbufferStorageMultisample :: (target: GLenum, samples: GLsizei, internalforamt: GLenum, width: GLsizei, height: GLsizei) -> void #foreign "gl" "renderbufferStorageMultisample" ---
+renderbufferStorage :: (target: GLenum, internalformat: GLenum, width: GLsizei, height: GLsizei) -> void #foreign "gl" "renderbufferStorage" ---
+renderbufferStorageMultisample :: (target: GLenum, samples: GLsizei, internalformat: GLenum, width: GLsizei, height: GLsizei) -> void #foreign "gl" "renderbufferStorageMultisample" ---
sampleCoverage :: (value: GLclampf, invert: GLboolean) -> void #foreign "gl" "sampleCoverage" ---
scissor :: (x: GLint, y: GLint, width: GLsizei, height: GLsizei) -> void #foreign "gl" "scissor" ---
setSize :: (width: GLint, y: GLint) -> void #foreign "gl" "setSize" ---
texImage2D :: (target: GLenum, level: GLint, internalFormat: GLenum, width: GLsizei, height: GLsizei, border: GLint, format: GLenum, type: GLenum, pixels: str) -> void #foreign "gl" "texImage2D" ---
texParameterf :: (target: GLenum, pname: GLenum, param: GLfloat) -> void #foreign "gl" "texParameterf" ---
texParameteri :: (target: GLenum, pname: GLenum, param: GLint) -> void #foreign "gl" "texParameteri" ---
+texStorage2D :: (target: GLenum, levels: GLsizei, internalformat: GLenum, width: GLsizei, height: GLsizei) -> void #foreign "gl" "texStorage2D" ---
texSubImage2D :: (target: GLenum, level: GLint, xoff: GLint, yoff: GLint, width: GLsizei, height: GLsizei, format: GLenum, type: GLenum, pixels: str) -> void #foreign "gl" "texSubImage2D" ---
uniform1f :: (loc: GLUniformLocation, x: GLfloat) -> void #foreign "gl" "uniform1f" ---
uniform1i :: (loc: GLUniformLocation, x: GLint) -> void #foreign "gl" "uniform1i" ---
}
AstNode* try_symbol_raw_resolve_from_node(AstNode* node, char* symbol) {
- // CLEANUP: So many checks for null....
- if (!node) return NULL;
-
- if (node->kind == Ast_Kind_Type_Raw_Alias)
- node = (AstNode *) ((AstTypeRawAlias *) node)->to->ast_type;
+ b32 used_pointer = 0;
- if (!node) return NULL;
+ while (1) {
+ if (!node) return NULL;
- if (node->kind == Ast_Kind_Type_Alias)
- node = (AstNode *) ((AstTypeAlias *) node)->to;
+ switch (node->kind) {
+ case Ast_Kind_Type_Raw_Alias: node = (AstNode *) ((AstTypeRawAlias *) node)->to->ast_type; break;
+ case Ast_Kind_Type_Alias: node = (AstNode *) ((AstTypeAlias *) node)->to; break;
+ case Ast_Kind_Pointer_Type: {
+ if (used_pointer) goto all_types_peeled_off;
+ used_pointer = 1;
- if (!node) return NULL;
+ node = (AstNode *) ((AstPointerType *) node)->elem;
+ break;
+ }
- // A single pointer can be dereferenced to lookup symbols in struct.
- if (node->kind == Ast_Kind_Pointer_Type)
- node = (AstNode *) ((AstPointerType *) node)->elem;
+ default: goto all_types_peeled_off;
+ }
+ }
+all_types_peeled_off:
if (!node) return NULL;
switch (node->kind) {