Add all the 2d drawing commands from the Cubyz-java (except from text).

This commit is contained in:
IntegratedQuantum 2022-08-28 13:27:43 +02:00
parent 1be03cf5f8
commit a852725a9f
14 changed files with 614 additions and 3 deletions

View File

@ -0,0 +1,19 @@
#version 330
layout (location=0) out vec4 frag_color;
flat in vec4 color;
in vec2 unitPosition;
// Like smooth step, but with linear interpolation instead of s-curve.
float linearstep(float edge0, float edge1, float x) {
return clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);
}
void main(){
float distSqr = sqrt(dot(unitPosition, unitPosition));
float delta = fwidth(distSqr)/2;
float alpha = linearstep(1+delta, 1-delta, distSqr);
frag_color = color;
frag_color.a *= alpha;
}

View File

@ -0,0 +1,29 @@
#version 330 core
layout (location=0) in vec2 vertex_pos;
flat out vec4 color;
out vec2 unitPosition;
//in pixel
uniform vec2 center;
uniform float radius;
uniform vec2 screen;
uniform int circleColor;
void main() {
// Convert to opengl coordinates:
vec2 position_percentage = (center + vertex_pos*radius)/screen;
vec2 position = vec2(position_percentage.x, -position_percentage.y)*2+vec2(-1, 1);
gl_Position = vec4(position, 0, 1);
color = vec4((circleColor & 0xff0000)>>16, (circleColor & 0xff00)>>8, circleColor & 0xff, (circleColor>>24) & 255)/255.0;
unitPosition = vertex_pos;
}

View File

@ -0,0 +1,11 @@
#version 330
layout (location=0) out vec4 frag_color;
uniform sampler2D image;
flat in vec4 fColor;
in vec2 uv;
void main() {
frag_color = texture(image, uv) * fColor;
}

View File

@ -0,0 +1,26 @@
#version 330 core
layout (location=0) in vec2 vertex_pos;
out vec2 uv;
flat out vec4 fColor;
//in pixel
uniform vec2 start;
uniform vec2 size;
uniform vec2 screen;
uniform int color;
void main() {
// Convert to opengl coordinates:
vec2 position_percentage = (start + vertex_pos*size)/screen;
vec2 position = vec2(position_percentage.x, -position_percentage.y)*2+vec2(-1, 1);
gl_Position = vec4(position, 0, 1);
fColor = vec4((color & 0xff0000)>>16, (color & 0xff00)>>8, color & 0xff, (color>>24) & 255)/255.0;
uv = vertex_pos;
}

View File

@ -0,0 +1,11 @@
#version 330
layout (location=0) out vec4 frag_color;
flat in vec4 color;
uniform sampler2D texture_sampler;
void main() {
frag_color = color;
}

View File

@ -0,0 +1,26 @@
#version 330 core
layout (location=0) in vec2 vertex_pos;
flat out vec4 color;
//in pixel
uniform vec2 start;
uniform vec2 direction;
uniform vec2 screen;
uniform int lineColor;
void main() {
// Convert to opengl coordinates:
vec2 position_percentage = (start + vertex_pos*direction)/screen;
vec2 position = vec2(position_percentage.x, -position_percentage.y)*2+vec2(-1, 1);
gl_Position = vec4(position, 0, 1);
color = vec4((lineColor & 0xff0000)>>16, (lineColor & 0xff00)>>8, lineColor & 0xff, (lineColor>>24) & 255)/255.0;
}

View File

@ -0,0 +1,9 @@
#version 330
layout (location=0) out vec4 frag_color;
flat in vec4 color;
void main(){
frag_color = color;
}

View File

@ -0,0 +1,26 @@
#version 330 core
layout (location=0) in vec2 vertex_pos;
flat out vec4 color;
//in pixel
uniform vec2 start;
uniform vec2 size;
uniform vec2 screen;
uniform int rectColor;
void main() {
// Convert to opengl coordinates:
vec2 position_percentage = (start + vertex_pos*size)/screen;
vec2 position = vec2(position_percentage.x, -position_percentage.y)*2+vec2(-1, 1);
gl_Position = vec4(position, 0, 1);
color = vec4((rectColor & 0xff0000)>>16, (rectColor & 0xff00)>>8, rectColor & 0xff, (rectColor>>24) & 255)/255.0;;
}

View File

@ -0,0 +1,37 @@
#version 330
layout (location=0) out vec4 frag_color;
in vec2 frag_face_pos;
in vec4 color;
uniform sampler2D texture_sampler;
//in pxls
uniform vec4 texture_rect;
uniform vec2 fontSize;
uniform int fontEffects;
vec2 convert2Proportional(vec2 original, vec2 full){
return vec2(original.x/full.x, original.y/full.y);
}
void main(){
vec4 texture_rect_percentage = vec4(convert2Proportional(texture_rect.xy, fontSize), convert2Proportional(texture_rect.zw, fontSize));
vec2 texture_position = vec2(
texture_rect_percentage.x+
frag_face_pos.x*texture_rect_percentage.z
,
texture_rect_percentage.y+
frag_face_pos.y*texture_rect_percentage.w
);
if ((fontEffects & 0x01000000) != 0) { // make it bold in y by sampling more pixels.
vec2 pixel_offset = 1/fontSize;
frag_color = color*max(texture(texture_sampler, texture_position),
texture(texture_sampler, texture_position + vec2(0, 0.5f/fontSize.y)));
} else {
frag_color = color*texture(texture_sampler,
texture_position);
}
}

View File

@ -0,0 +1,42 @@
#version 330
layout (location=0) in vec2 in_vertex_pos;
layout (location=1) in vec2 face_pos;
out vec2 frag_face_pos;
out vec4 color;
//in pixel
uniform vec4 texture_rect;
uniform vec2 scene;
uniform vec2 offset;
uniform vec2 fontSize;
uniform float ratio;
uniform int fontEffects;
uniform float alpha;
vec2 convert2Proportional(vec2 original, vec2 full) {
return vec2(original.x/full.x, original.y/full.y);
}
void main() {
vec2 vertex_pos = in_vertex_pos;
vec2 position_percentage = convert2Proportional(offset*ratio, scene);
vec2 size_percentage = convert2Proportional(vec2(texture_rect.z, texture_rect.w)*ratio, scene);
if ((fontEffects & 0x02000000) != 0) { // italic
vertex_pos.x += vertex_pos.y/texture_rect.z;
}
//convert glyph coords to opengl coords
vec4 rect = vec4(position_percentage, size_percentage);
vec2 position = vec2(rect.x+vertex_pos.x*rect.z, -rect.y+vertex_pos.y*rect.w)*2+vec2(-1, 1);
gl_Position = vec4(position, 0, 1);
frag_face_pos = face_pos;
color = vec4(vec3((fontEffects & 0xff0000)>>16, (fontEffects & 0xff00)>>8, fontEffects & 0xff)/255.0, alpha);
}

View File

@ -0,0 +1,9 @@
#version 430
layout (location=0) out vec4 frag_color;
uniform vec3 lineColor;
void main() {
frag_color = vec4(lineColor, 1);
}

View File

@ -0,0 +1,25 @@
#version 430 core
//in pixel
uniform vec2 start;
uniform vec2 dimension;
uniform vec2 screen;
uniform int points;
uniform int offset;
layout(std430, binding = 4) buffer _data
{
float data[];
};
void main() {
float x = gl_VertexID;
float y = -data[(gl_VertexID+offset)%points];
// Convert to opengl coordinates:
vec2 position_percentage = (start + dimension*vec2(x/points, y))/screen;
vec2 position = vec2(position_percentage.x, -position_percentage.y)*2 + vec2(-1, 1);
gl_Position = vec4(position, 0, 1);
}

View File

@ -2,6 +2,10 @@
/// Also contains some basic 2d drawing stuff.
const std = @import("std");
const Vec4i = @import("vec.zig").Vec4i;
const Vec2f = @import("vec.zig").Vec2f;
const Window = @import("main.zig").Window;
const Allocator = std.mem.Allocator;
@ -14,19 +18,317 @@ fn fileToString(allocator: Allocator, path: []const u8) ![]u8 {
return file.readToEndAlloc(allocator, std.math.maxInt(usize));
}
pub fn init() void {
pub const Draw = struct {
var color: i32 = 0;
var clip: ?Vec4i = null;
pub fn setColor(newColor: u32) void {
color = @bitCast(i32, newColor);
}
/// Returns the previous clip.
pub fn setClip(newClip: Vec4i) ?Vec4i {
const oldClip = clip;
clip = newClip;
var clipRef: *Vec4i = &clip.?;
if(oldClip == null) {
c.glEnable(c.GL_SCISSOR_TEST);
} else {
if (clipRef.x < oldClip.x) {
clipRef.z -= oldClip.x - clipRef.x;
clipRef.x += oldClip.x - clipRef.x;
}
if (clipRef.y < oldClip.y) {
clipRef.w -= oldClip.y - clipRef.y;
clipRef.y += oldClip.y - clipRef.y;
}
if (clipRef.x + clipRef.z > oldClip.x + oldClip.z) {
clipRef.z -= (clipRef.x + clipRef.z) - (oldClip.x + oldClip.z);
}
if (clipRef.y + clipRef.w > oldClip.y + oldClip.w) {
clipRef.w -= (clipRef.y + clipRef.w) - (oldClip.y + oldClip.w);
}
}
c.glScissor(clipRef.x, clipRef.y, clipRef.z, clipRef.w);
return oldClip;
}
/// Should be used to restore the old clip when leaving the render function.
pub fn restoreClip(previousClip: ?Vec4i) void {
clip = previousClip;
if (clip) |clipRef| {
c.glScissor(clipRef.x, clipRef.y, clipRef.z, clipRef.w);
} else {
c.glDisable(c.GL_SCISSOR_TEST);
}
}
// ----------------------------------------------------------------------------
// Stuff for fillRect:
var rectUniforms: struct {
screen: c_int,
start: c_int,
size: c_int,
rectColor: c_int,
} = undefined;
var rectShader: Shader = undefined;
var rectVAO: c_uint = undefined;
var rectVBO: c_uint = undefined;
fn initRect() void {
rectShader = Shader.create("assets/cubyz/shaders/graphics/Rect.vs", "assets/cubyz/shaders/graphics/Rect.fs") catch Shader{.id = 0};
rectUniforms = rectShader.bulkGetUniformLocation(@TypeOf(rectUniforms));
var rawData = [_]f32 {
0, 0,
0, 1,
1, 0,
1, 1,
};
c.glGenVertexArrays(1, &rectVAO);
c.glBindVertexArray(rectVAO);
c.glGenBuffers(1, &rectVBO);
c.glBindBuffer(c.GL_ARRAY_BUFFER, rectVBO);
c.glBufferData(c.GL_ARRAY_BUFFER, rawData.len*@sizeOf(f32), &rawData, c.GL_STATIC_DRAW);
c.glVertexAttribPointer(0, 2, c.GL_FLOAT, c.GL_FALSE, 2*@sizeOf(f32), null);
c.glEnableVertexAttribArray(0);
}
fn deinitRect() void {
rectShader.delete();
c.glDeleteVertexArrays(1, &rectVAO);
c.glDeleteBuffers(1, &rectVBO);
}
pub fn rect(pos: Vec2f, dim: Vec2f) void {
rectShader.bind();
c.glUniform2f(rectUniforms.screen, @intToFloat(f32, Window.width), @intToFloat(f32, Window.height));
c.glUniform2f(rectUniforms.start, pos.x, pos.y);
c.glUniform2f(rectUniforms.size, dim.x, dim.y);
c.glUniform1i(rectUniforms.rectColor, color);
c.glBindVertexArray(rectVAO);
c.glDrawArrays(c.GL_TRIANGLE_STRIP, 0, 4);
}
// ----------------------------------------------------------------------------
// Stuff for drawLine:
var lineUniforms: struct {
screen: c_int,
start: c_int,
direction: c_int,
lineColor: c_int,
} = undefined;
var lineShader: Shader = undefined;
var lineVAO: c_uint = undefined;
var lineVBO: c_uint = undefined;
fn initLine() void {
lineShader = Shader.create("assets/cubyz/shaders/graphics/Line.vs", "assets/cubyz/shaders/graphics/Line.fs") catch Shader{.id = 0};
lineUniforms = lineShader.bulkGetUniformLocation(@TypeOf(lineUniforms));
var rawData = [_]f32 {
0, 0,
1, 1,
};
c.glGenVertexArrays(1, &lineVAO);
c.glBindVertexArray(lineVAO);
c.glGenBuffers(1, &lineVBO);
c.glBindBuffer(c.GL_ARRAY_BUFFER, lineVBO);
c.glBufferData(c.GL_ARRAY_BUFFER, rawData.len*@sizeOf(f32), &rawData, c.GL_STATIC_DRAW);
c.glVertexAttribPointer(0, 2, c.GL_FLOAT, c.GL_FALSE, 2*@sizeOf(f32), null);
c.glEnableVertexAttribArray(0);
}
fn deinitLine() void {
lineShader.delete();
c.glDeleteVertexArrays(1, &lineVAO);
c.glDeleteBuffers(1, &lineVBO);
}
pub fn line(pos1: Vec2f, pos2: Vec2f) void {
lineShader.bind();
c.glUniform2f(lineUniforms.screen, @intToFloat(f32, Window.width), @intToFloat(f32, Window.height));
c.glUniform2f(lineUniforms.start, pos1.x, pos1.y);
c.glUniform2f(lineUniforms.direction, pos2.x - pos1.x, pos2.y - pos1.y);
c.glUniform1i(lineUniforms.lineColor, color);
c.glBindVertexArray(lineVAO);
c.glDrawArrays(c.GL_LINE_STRIP, 0, 2);
}
// ----------------------------------------------------------------------------
// Stuff for drawRect:
// Draw rect can use the same shader as drawline, because it essentially draws lines.
var drawRectVAO: c_uint = undefined;
var drawRectVBO: c_uint = undefined;
fn initDrawRect() void {
var rawData = [_]f32 {
0, 0,
0, 1,
1, 1,
1, 0,
};
c.glGenVertexArrays(1, &drawRectVAO);
c.glBindVertexArray(drawRectVAO);
c.glGenBuffers(1, &drawRectVBO);
c.glBindBuffer(c.GL_ARRAY_BUFFER, drawRectVBO);
c.glBufferData(c.GL_ARRAY_BUFFER, rawData.len*@sizeOf(f32), &rawData, c.GL_STATIC_DRAW);
c.glVertexAttribPointer(0, 2, c.GL_FLOAT, c.GL_FALSE, 2*@sizeOf(f32), null);
c.glEnableVertexAttribArray(0);
}
fn deinitDrawRect() void {
c.glDeleteVertexArrays(1, &drawRectVAO);
c.glDeleteBuffers(1, &drawRectVBO);
}
pub fn rectOutline(pos: Vec2f, dim: Vec2f) void {
lineShader.bind();
c.glUniform2f(lineUniforms.screen, @intToFloat(f32, Window.width), @intToFloat(f32, Window.height));
c.glUniform2f(lineUniforms.start, pos.x, pos.y); // Move the coordinates, so they are in the center of a pixel.
c.glUniform2f(lineUniforms.direction, dim.x - 1, dim.y - 1); // The height is a lot smaller because the inner edge of the rect is drawn.
c.glUniform1i(lineUniforms.lineColor, color);
c.glBindVertexArray(lineVAO);
c.glDrawArrays(c.GL_LINE_LOOP, 0, 5);
}
// ----------------------------------------------------------------------------
// Stuff for fillCircle:
var circleUniforms: struct {
screen: c_int,
center: c_int,
radius: c_int,
circleColor: c_int,
} = undefined;
var circleShader: Shader = undefined;
var circleVAO: c_uint = undefined;
var circleVBO: c_uint = undefined;
fn initCircle() void {
circleShader = Shader.create("assets/cubyz/shaders/graphics/Circle.vs", "assets/cubyz/shaders/graphics/Circle.fs") catch Shader{.id = 0};
circleUniforms = circleShader.bulkGetUniformLocation(@TypeOf(circleUniforms));
var rawData = [_]f32 {
-1, -1,
-1, 1,
1, -1,
1, 1,
};
c.glGenVertexArrays(1, &circleVAO);
c.glBindVertexArray(circleVAO);
c.glGenBuffers(1, &circleVBO);
c.glBindBuffer(c.GL_ARRAY_BUFFER, circleVBO);
c.glBufferData(c.GL_ARRAY_BUFFER, rawData.len*@sizeOf(f32), &rawData, c.GL_STATIC_DRAW);
c.glVertexAttribPointer(0, 2, c.GL_FLOAT, c.GL_FALSE, 2*@sizeOf(f32), null);
c.glEnableVertexAttribArray(0);
}
fn deinitCircle() void {
circleShader.delete();
c.glDeleteVertexArrays(1, &circleVAO);
c.glDeleteBuffers(1, &circleVBO);
}
pub fn circle(center: Vec2f, radius: f32) void {
circleShader.bind();
c.glUniform2f(circleUniforms.screen, @intToFloat(f32, Window.width), @intToFloat(f32, Window.height));
c.glUniform2f(circleUniforms.center, center.x, center.y); // Move the coordinates, so they are in the center of a pixel.
c.glUniform1f(circleUniforms.radius, radius); // The height is a lot smaller because the inner edge of the rect is drawn.
c.glUniform1i(circleUniforms.circleColor, color);
c.glBindVertexArray(circleVAO);
c.glDrawArrays(c.GL_TRIANGLE_STRIP, 0, 4);
}
// ----------------------------------------------------------------------------
// Stuff for drawImage:
// Luckily the vao of the regular rect can used.
var imageUniforms: struct {
screen: c_int,
start: c_int,
size: c_int,
image: c_int,
color: c_int,
} = undefined;
var imageShader: Shader = undefined;
fn initImage() void {
imageShader = Shader.create("assets/cubyz/shaders/graphics/Circle.vs", "assets/cubyz/shaders/graphics/Circle.fs") catch Shader{.id = 0};
imageUniforms = imageShader.bulkGetUniformLocation(@TypeOf(imageUniforms));
}
fn deinitImage() void {
imageShader.delete();
}
pub fn boundImage(pos: Vec2f, dim: Vec2f) void {
imageShader.bind();
c.glUniform2f(imageUniforms.screen, @intToFloat(f32, Window.width), @intToFloat(f32, Window.height));
c.glUniform2f(imageUniforms.start, pos.x, pos.y);
c.glUniform2f(imageUniforms.size, dim.x, dim.y);
c.glUniform1i(imageUniforms.color, color);
c.glBindVertexArray(rectVAO);
c.glDrawArrays(c.GL_TRIANGLE_STRIP, 0, 4);
}
// // ----------------------------------------------------------------------------
// // TODO: Stuff for drawText:
//
// private static CubyzFont font;
// private static float fontSize;
// public static void setFont(CubyzFont font, float fontSize) {
// Graphics.font = font;
// Graphics.fontSize = fontSize;
// }
//
// /**
// * Draws a given string.
// * Uses TextLine.
// * @param x left
// * @param y top
// * @param text
// */
// public static void drawText(float x, float y, String text) {
// text = String.format("#%06x", 0xffffff & color) + text; // Add the coloring information.
// TextLine line = new TextLine(font, text, fontSize, false);
// line.render(x, y);
// }
};
pub fn init() void {
Draw.initCircle();
Draw.initDrawRect();
Draw.initImage();
Draw.initLine();
Draw.initRect();
}
pub fn deinit() void {
Draw.deinitCircle();
Draw.deinitDrawRect();
Draw.deinitImage();
Draw.deinitLine();
Draw.deinitRect();
}
pub const Shader = struct {
id: c_uint,
fn addShader(self: *const Shader, filename: []const u8, shader_stage: c_uint) !void {
const source = try fileToString(std.heap.page_allocator, filename);
const source = fileToString(std.heap.page_allocator, filename) catch |err| {
std.log.warn("Couldn't find file: {s}", .{filename});
return err;
};
defer std.heap.page_allocator.free(source);
const ref_buffer = [_] [*c]u8 {@ptrCast([*c]u8, source.ptr)};
const shader = c.glCreateShader(shader_stage);

View File

@ -2,6 +2,8 @@ const std = @import("std");
const graphics = @import("graphics.zig");
const Vec2f = @import("vec.zig").Vec2f;
pub const c = @cImport ({
@cInclude("glad/glad.h");
@cInclude("GLFW/glfw3.h");
@ -56,6 +58,12 @@ pub const Window = struct {
width = @intCast(u31, newWidth);
height = @intCast(u31, newHeight);
}
fn glDebugOutput(_: c_uint, typ: c_uint, _: c_uint, severity: c_uint, length: c_int, message: [*c]const u8, _: ?*const anyopaque) callconv(.C) void {
if(typ == c.GL_DEBUG_TYPE_ERROR or typ == c.GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR or typ == c.GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR or typ == c.GL_DEBUG_TYPE_PORTABILITY or typ == c.GL_DEBUG_TYPE_PERFORMANCE) {
std.log.err("OpenGL {}:{s}", .{severity, message[0..@intCast(usize, length)]});
@panic("OpenGL error");
}
}
};
fn init() !void {
@ -65,6 +73,9 @@ pub const Window = struct {
return error.GLFWFailed;
}
if(@import("builtin").mode == .Debug) {
c.glfwWindowHint(c.GLFW_OPENGL_DEBUG_CONTEXT, 1);
}
c.glfwWindowHint(c.GLFW_CONTEXT_VERSION_MAJOR, 4);
c.glfwWindowHint(c.GLFW_CONTEXT_VERSION_MINOR, 3);
@ -79,6 +90,13 @@ pub const Window = struct {
return error.GLADFailed;
}
c.glfwSwapInterval(1);
if(@import("builtin").mode == .Debug) {
c.glEnable(c.GL_DEBUG_OUTPUT);
c.glEnable(c.GL_DEBUG_OUTPUT_SYNCHRONOUS);
c.glDebugMessageCallback(GLFWCallbacks.glDebugOutput, null);
c.glDebugMessageControl(c.GL_DONT_CARE, c.GL_DONT_CARE, c.GL_DONT_CARE, 0, null, c.GL_TRUE);
}
}
fn deinit() void {
@ -120,6 +138,11 @@ pub fn main() !void {
graphics.init();
defer graphics.deinit();
c.glEnable(c.GL_CULL_FACE);
c.glCullFace(c.GL_BACK);
c.glEnable(c.GL_BLEND);
c.glBlendFunc(c.GL_SRC_ALPHA, c.GL_ONE_MINUS_SRC_ALPHA);
while(c.glfwWindowShouldClose(Window.window) == 0) {
{ // Check opengl errors:
const err = c.glGetError();
@ -130,6 +153,22 @@ pub fn main() !void {
c.glfwSwapBuffers(Window.window);
c.glfwPollEvents();
c.glViewport(0, 0, Window.width, Window.height);
c.glClearColor(1, 1, 0, 1);
c.glClear(c.GL_DEPTH_BUFFER_BIT | c.GL_COLOR_BUFFER_BIT);
{ // Render the game
c.glEnable(c.GL_DEPTH_TEST);
// TODO
}
{ // Render the GUI
c.glDisable(c.GL_DEPTH_TEST);
graphics.Draw.setColor(0xff0000ff);
graphics.Draw.rect(Vec2f{.x = 100, .y = 100}, Vec2f{.x = 200, .y = 100});
graphics.Draw.circle(Vec2f{.x = 200, .y = 200}, 59);
graphics.Draw.setColor(0xffff00ff);
graphics.Draw.line(Vec2f{.x = 0, .y = 0}, Vec2f{.x = 1920, .y = 1080});
}
}
std.log.info("Hello zig.", .{});