Initial commit
This commit is contained in:
commit
a06aacd405
212
src/k3.h
Normal file
212
src/k3.h
Normal file
@ -0,0 +1,212 @@
|
||||
#pragma once
|
||||
|
||||
#include<stddef.h>
|
||||
#include<stdint.h>
|
||||
#include<cglm/vec3.h>
|
||||
#include<cglm/mat4.h>
|
||||
#include<cglm/quat.h>
|
||||
|
||||
void k3Init();
|
||||
void k3Resize(uint16_t width, uint16_t height);
|
||||
|
||||
enum k3TexType {
|
||||
k3_DIFFUSE, k3_NORMAL, k3_DISPLACEMENT, k3_EMISSION, k3_ROUGHNESS, k3_ALPHA,
|
||||
k3_DEPTH,
|
||||
k3_CUBEMAP,
|
||||
k3_RAWCOLOR,
|
||||
};
|
||||
|
||||
struct k3Tex;
|
||||
struct k3Tex *k3TexCreate(enum k3TexType type);
|
||||
void k3TexUpdate(struct k3Tex*, enum k3TexType type, int index, uint16_t width, uint16_t height, void *data);
|
||||
uint32_t k3TexSzX(struct k3Tex*);
|
||||
uint32_t k3TexSzY(struct k3Tex*);
|
||||
uint32_t k3TexSzZ(struct k3Tex*);
|
||||
|
||||
struct k3GLSLV;
|
||||
struct k3GLSLV *k3ShaderGLSLV(const char *src_, const char*(*ldr)(const char *fn));
|
||||
|
||||
struct k3GLSLF;
|
||||
struct k3GLSLF *k3ShaderGLSLF(const char *src_, const char*(*ldr)(const char *fn));
|
||||
|
||||
struct k3GLSLG;
|
||||
struct k3GLSLG *k3ShaderGLSLG(const char *src_, const char*(*ldr)(const char *fn));
|
||||
|
||||
struct k3GLSLP;
|
||||
struct k3GLSLP *k3ProgramGLSL(struct k3GLSLV*, struct k3GLSLF*, struct k3GLSLG*);
|
||||
uint16_t k3ProgramGetUId(struct k3GLSLP*, const char *key);
|
||||
|
||||
struct k3ARBVP;
|
||||
struct k3ARBVP *k3ProgramARBVP(const char *src);
|
||||
|
||||
struct k3ARBFP;
|
||||
struct k3ARBFP *k3ProgramARBFP(const char *src);
|
||||
|
||||
extern uint8_t k3GraphicalReduction;
|
||||
extern int k3IsCore;
|
||||
|
||||
struct k3Mat {
|
||||
struct {
|
||||
vec4 diffuse;
|
||||
vec4 specular;
|
||||
vec4 emission;
|
||||
float shininess;
|
||||
} primitive;
|
||||
struct {
|
||||
struct {
|
||||
struct k3ARBVP *vp;
|
||||
} arbvp;
|
||||
struct {
|
||||
struct k3ARBFP *fp;
|
||||
} arbfp;
|
||||
struct {
|
||||
struct k3GLSLP *hp;
|
||||
|
||||
#ifdef k3_IRREGULAR_SHADOWS
|
||||
struct k3GLSLP *hpIrreg1;
|
||||
struct k3GLSLP *hpIrreg2;
|
||||
#endif
|
||||
|
||||
uint8_t uCount;
|
||||
struct {
|
||||
char name[16];
|
||||
int8_t id;
|
||||
#define k3_MAT_UNIFORM_I1 0
|
||||
#define k3_MAT_UNIFORM_F1 4
|
||||
uint8_t type;
|
||||
union {
|
||||
int i1;
|
||||
float f1;
|
||||
};
|
||||
#define k3_MAX_GLSL_UNIFORMS 8
|
||||
} u[k3_MAX_GLSL_UNIFORMS];
|
||||
} glsl;
|
||||
|
||||
#define k3_MAX_GLSL_UNITS 8
|
||||
struct k3Tex *units[k3_MAX_GLSL_UNITS];
|
||||
int unitsUsed;
|
||||
|
||||
float aabb;
|
||||
char additive;
|
||||
char transparent;
|
||||
char nocull;
|
||||
char alphatest;
|
||||
} passes[1];
|
||||
};
|
||||
|
||||
struct k3AnimationBone {
|
||||
vec4 translation;
|
||||
versor rotation;
|
||||
};
|
||||
struct k3Animation {
|
||||
struct k3AnimationBone *frames;
|
||||
mat4 *invBind;
|
||||
uint8_t *boneParents;
|
||||
uint16_t fps;
|
||||
uint16_t frameCount;
|
||||
uint16_t boneCount;
|
||||
uint16_t id;
|
||||
};
|
||||
|
||||
struct k3Animator {
|
||||
float time;
|
||||
int loop;
|
||||
|
||||
mat4 *inter;
|
||||
|
||||
struct k3Animation *base;
|
||||
};
|
||||
|
||||
struct k3Offscreen;
|
||||
|
||||
enum k3LightType {
|
||||
k3_DIRECTIONAL,
|
||||
k3_SPOT,
|
||||
k3_OMNI,
|
||||
k3_HALF_OMNI,
|
||||
k3_AMBIENT,
|
||||
};
|
||||
struct k3Light {
|
||||
enum k3LightType type;
|
||||
_Alignas(16) int castShadow;
|
||||
_Alignas(16) vec4 color;
|
||||
_Alignas(16) float radius;
|
||||
_Alignas(16) union {
|
||||
struct {
|
||||
vec4 direction;
|
||||
} dir;
|
||||
struct {
|
||||
vec4 position;
|
||||
vec4 direction;
|
||||
float angle;
|
||||
} spot;
|
||||
struct {
|
||||
vec4 position;
|
||||
} omni;
|
||||
};
|
||||
};
|
||||
|
||||
struct k3Mesh {
|
||||
uint16_t idxStart, idxNumber;
|
||||
struct k3Mat mat;
|
||||
};
|
||||
|
||||
struct k3Storage;
|
||||
void k3StorageRef(struct k3Storage*);
|
||||
void k3StorageUnref(struct k3Storage*);
|
||||
|
||||
struct k3Mdl;
|
||||
struct k3Mdl *k3MdlCreate(size_t verts, size_t indices, size_t boneCount, vec3 *pos, uint8_t *nrm, float *uvs, uint8_t *cols, uint8_t *boneids, uint16_t *boneweights, uint16_t *inds, mat4 *invBind, uint8_t *boneParents);
|
||||
void k3MdlUpdatePos(struct k3Mdl *mdl, vec3 *pos);
|
||||
void k3MdlAddMesh(struct k3Mdl*, struct k3Mat*, uint16_t idxStart, uint16_t idxNumber);
|
||||
struct k3Mesh *k3MdlGetMeshes(struct k3Mdl*, size_t *count);
|
||||
void k3MdlAddAnim(struct k3Mdl*, struct k3Animation*);
|
||||
struct k3Animation *k3MdlGetAnim(struct k3Mdl*, uint16_t id);
|
||||
size_t k3MdlGetBoneCount(struct k3Mdl*);
|
||||
|
||||
void k3MdlSetDebugName(struct k3Mdl*, const char*);
|
||||
|
||||
struct k3Mdl *k3MdlCopySubs(struct k3Mdl*);
|
||||
|
||||
void k3AnimatorSet(struct k3Animator*, float);
|
||||
void k3AnimatorStep(struct k3Animator*, float);
|
||||
|
||||
void k3SetLights(size_t, struct k3Light*);
|
||||
struct k3Light *k3GetLights(size_t*);
|
||||
|
||||
void k3Clear();
|
||||
|
||||
void k3Batch(struct k3Mdl*, mat4, struct k3AnimationBone* bones);
|
||||
void k3BatchClear();
|
||||
|
||||
void k3PassForward(mat4 projection, mat4 cam);
|
||||
void k3PassDepthOnly(mat4 projection, mat4 cam, int clear, int cull);
|
||||
|
||||
void k3PassShadowmap(mat4 projection, mat4 cam, struct k3Offscreen *offscr);
|
||||
|
||||
struct k3Offscreen;
|
||||
struct k3Offscreen *k3OffscreenCreate(struct k3Tex *diffuse, struct k3Tex *depth);
|
||||
void k3BeginOffscreen(struct k3Offscreen*);
|
||||
void k3EndOffscreen(struct k3Offscreen*);
|
||||
void k3OffscreenDestroy(struct k3Offscreen*);
|
||||
|
||||
#define k3_NONE 0
|
||||
#define k3_GLSL 1
|
||||
#define k3_ARBFRAG 2
|
||||
void k3BlitToScreenEffect(struct k3Offscreen *offscr, int additive, int effect, void *program, void *params);
|
||||
void k3BlitToScreen(struct k3Offscreen *offscr, int additive);
|
||||
|
||||
int k3CubemapTraditional(struct k3Tex*, mat4 proj, mat4 cam);
|
||||
|
||||
void k3SetTime(float t);
|
||||
|
||||
enum k3LogLevel {
|
||||
k3_DEBUG, k3_INFO, k3_WARN, k3_ERR
|
||||
};
|
||||
typedef void(*k3LogCallback)(enum k3LogLevel, const char *str, size_t len);
|
||||
void k3SetLogCallback(k3LogCallback);
|
||||
void k3Log(enum k3LogLevel, const char *format, ...);
|
||||
|
||||
uint16_t k3TexSzMax();
|
||||
|
||||
void k3PassIrregular(struct k3Offscreen *main, mat4 mainproj, mat4 maincam);
|
224
src/k3batch.c
Normal file
224
src/k3batch.c
Normal file
@ -0,0 +1,224 @@
|
||||
#include"k3batch.h"
|
||||
|
||||
#include"gl.h"
|
||||
#include<string.h>
|
||||
|
||||
struct S {
|
||||
struct k3RectF src;
|
||||
struct k3RectF dst;
|
||||
vec4 color;
|
||||
float rot;
|
||||
char additive;
|
||||
};
|
||||
|
||||
static struct k3Tex *activeTex;
|
||||
static size_t SCount, SCapacity;
|
||||
static struct S *S;
|
||||
|
||||
static struct k3GLSLP *coreProg;
|
||||
static GLuint coreVBO;
|
||||
|
||||
void k3BatchInit() {
|
||||
if(k3IsCore) {
|
||||
coreProg = k3ProgramGLSL(k3ShaderGLSLV(
|
||||
"#version 330\n"
|
||||
"in vec2 a_pos;\n"
|
||||
"in vec2 a_uv;\n"
|
||||
"in vec4 a_color;\n"
|
||||
"out vec2 v_uv;\n"
|
||||
"out vec4 v_color;\n"
|
||||
"void main() {\n"
|
||||
" v_uv = a_uv;\n"
|
||||
" v_color = a_color;\n"
|
||||
" gl_Position = vec4(vec2(a_pos.x / 3600.0, a_pos.y / 2025.0) * 2.0 - 1.0, 0.0, 1.0);\n"
|
||||
"}\n"
|
||||
, NULL), k3ShaderGLSLF(
|
||||
"#version 330\n"
|
||||
"uniform sampler2D u_tex;\n"
|
||||
"uniform float u_texuse;\n"
|
||||
"in vec2 v_uv;\n"
|
||||
"in vec4 v_color;\n"
|
||||
"out vec4 fragcolor;\n"
|
||||
"void main() {\n"
|
||||
" fragcolor = mix(vec4(1, 1, 1, 1), texture2D(u_tex, v_uv), u_texuse) * v_color;\n"
|
||||
"}\n"
|
||||
, NULL), NULL);
|
||||
|
||||
glGenBuffers(1, &coreVBO);
|
||||
}
|
||||
}
|
||||
|
||||
void k3BatchAdd(struct k3Tex *tex, struct k3RectF src, struct k3RectF dst, float rot, vec4 color) {
|
||||
if(activeTex != tex) {
|
||||
k3BatchFlush();
|
||||
activeTex = tex;
|
||||
}
|
||||
|
||||
if(SCount == SCapacity) {
|
||||
struct S *new = _mm_malloc(sizeof(*S) * (SCapacity + 32), 16);
|
||||
if(S) {
|
||||
memcpy(new, S, sizeof(*S) * SCapacity);
|
||||
_mm_free(S);
|
||||
}
|
||||
S = new;
|
||||
SCapacity += 32;
|
||||
}
|
||||
|
||||
S[SCount++] = (struct S) {
|
||||
.src = src,
|
||||
.dst = dst,
|
||||
.rot = rot,
|
||||
.color = {color[0], color[1], color[2], color[3]},
|
||||
};
|
||||
}
|
||||
|
||||
void k3BatchFlush() {
|
||||
if(!k3IsCore) {
|
||||
glDisable(GL_NORMALIZE);
|
||||
|
||||
// Some drivers crash on glEnable(GL_LIGHTING) *AND* glDisable(GL_LIGHTING) for some reason
|
||||
// Just don't do it unless fixed-function is explicitly on
|
||||
glDisable(GL_LIGHTING);
|
||||
if(!GLAD_GL_ARB_shading_language_100) {
|
||||
}
|
||||
}
|
||||
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
if(GLAD_GL_ARB_vertex_program) {
|
||||
glDisable(GL_VERTEX_PROGRAM_ARB);
|
||||
}
|
||||
if(GLAD_GL_ARB_fragment_program) {
|
||||
glDisable(GL_FRAGMENT_PROGRAM_ARB);
|
||||
}
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
if(activeTex) {
|
||||
if(!k3IsCore) glEnable(GL_TEXTURE_2D);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, *(GLuint*) activeTex);
|
||||
} else {
|
||||
if(!k3IsCore) glDisable(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
if(k3IsCore) {
|
||||
glUseProgram((GLuint) coreProg);
|
||||
|
||||
float *farr = alloca(SCount * 48 * sizeof(*farr));
|
||||
|
||||
struct S *s = S;
|
||||
for(size_t i = 0; i < SCount; i++) {
|
||||
farr[i * 48 + 0] = s->dst.x;
|
||||
farr[i * 48 + 1] = s->dst.y;
|
||||
farr[i * 48 + 2] = s->src.x;
|
||||
farr[i * 48 + 3] = s->src.y + s->src.h;
|
||||
farr[i * 48 + 4] = s->color[0];
|
||||
farr[i * 48 + 5] = s->color[1];
|
||||
farr[i * 48 + 6] = s->color[2];
|
||||
farr[i * 48 + 7] = s->color[3];
|
||||
|
||||
farr[i * 48 + 8] = s->dst.x + s->dst.w;
|
||||
farr[i * 48 + 9] = s->dst.y;
|
||||
farr[i * 48 + 10] = s->src.x + s->src.w;
|
||||
farr[i * 48 + 11] = s->src.y + s->src.h;
|
||||
farr[i * 48 + 12] = s->color[0];
|
||||
farr[i * 48 + 13] = s->color[1];
|
||||
farr[i * 48 + 14] = s->color[2];
|
||||
farr[i * 48 + 15] = s->color[3];
|
||||
|
||||
farr[i * 48 + 16] = s->dst.x + s->dst.w;
|
||||
farr[i * 48 + 17] = s->dst.y + s->dst.h;
|
||||
farr[i * 48 + 18] = s->src.x + s->src.w;
|
||||
farr[i * 48 + 19] = s->src.y;
|
||||
farr[i * 48 + 20] = s->color[0];
|
||||
farr[i * 48 + 21] = s->color[1];
|
||||
farr[i * 48 + 22] = s->color[2];
|
||||
farr[i * 48 + 23] = s->color[3];
|
||||
|
||||
farr[i * 48 + 24] = s->dst.x;
|
||||
farr[i * 48 + 25] = s->dst.y;
|
||||
farr[i * 48 + 26] = s->src.x;
|
||||
farr[i * 48 + 27] = s->src.y + s->src.h;
|
||||
farr[i * 48 + 28] = s->color[0];
|
||||
farr[i * 48 + 29] = s->color[1];
|
||||
farr[i * 48 + 30] = s->color[2];
|
||||
farr[i * 48 + 31] = s->color[3];
|
||||
|
||||
farr[i * 48 + 32] = s->dst.x + s->dst.w;
|
||||
farr[i * 48 + 33] = s->dst.y + s->dst.h;
|
||||
farr[i * 48 + 34] = s->src.x + s->src.w;
|
||||
farr[i * 48 + 35] = s->src.y;
|
||||
farr[i * 48 + 36] = s->color[0];
|
||||
farr[i * 48 + 37] = s->color[1];
|
||||
farr[i * 48 + 38] = s->color[2];
|
||||
farr[i * 48 + 39] = s->color[3];
|
||||
|
||||
farr[i * 48 + 40] = s->dst.x;
|
||||
farr[i * 48 + 41] = s->dst.y + s->dst.h;
|
||||
farr[i * 48 + 42] = s->src.x;
|
||||
farr[i * 48 + 43] = s->src.y;
|
||||
farr[i * 48 + 44] = s->color[0];
|
||||
farr[i * 48 + 45] = s->color[1];
|
||||
farr[i * 48 + 46] = s->color[2];
|
||||
farr[i * 48 + 47] = s->color[3];
|
||||
|
||||
s++;
|
||||
}
|
||||
|
||||
glBindBufferARB(GL_ARRAY_BUFFER_ARB, coreVBO);
|
||||
glBufferDataARB(GL_ARRAY_BUFFER_ARB, SCount * 48 * sizeof(*farr), farr, GL_DYNAMIC_DRAW);
|
||||
|
||||
glUniform1f(glGetUniformLocation((GLuint) coreProg, "u_texuse"), !!activeTex);
|
||||
|
||||
GLint aPos = glGetAttribLocation((GLuint) coreProg, "a_pos");
|
||||
GLint aUv = glGetAttribLocation((GLuint) coreProg, "a_uv");
|
||||
GLint aColor = glGetAttribLocation((GLuint) coreProg, "a_color");
|
||||
|
||||
glEnableVertexAttribArray(aPos);
|
||||
glEnableVertexAttribArray(aUv);
|
||||
glEnableVertexAttribArray(aColor);
|
||||
|
||||
glVertexAttribPointer(aPos, 2, GL_FLOAT, GL_FALSE, 32, (void*) 0);
|
||||
glVertexAttribPointer(aUv, 2, GL_FLOAT, GL_FALSE, 32, (void*) 8);
|
||||
glVertexAttribPointer(aColor, 4, GL_FLOAT, GL_FALSE, 32, (void*) 16);
|
||||
|
||||
glDrawArrays(GL_TRIANGLES, 0, SCount * 6);
|
||||
|
||||
glDisableVertexAttribArray(aPos);
|
||||
glDisableVertexAttribArray(aUv);
|
||||
glDisableVertexAttribArray(aColor);
|
||||
} else {
|
||||
if(GLAD_GL_ARB_shading_language_100) {
|
||||
glUseProgramObjectARB(0);
|
||||
}
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
struct S *s = S;
|
||||
for(size_t i = 0; i < SCount; i++) {
|
||||
glColor4f(s->color[0], s->color[1], s->color[2], s->color[3]);
|
||||
|
||||
glTexCoord2f(s->src.x, s->src.y + s->src.h);
|
||||
glVertex2f(s->dst.x, s->dst.y);
|
||||
|
||||
glTexCoord2f(s->src.x + s->src.w, s->src.y + s->src.h);
|
||||
glVertex2f(s->dst.x + s->dst.w, s->dst.y);
|
||||
|
||||
glTexCoord2f(s->src.x + s->src.w, s->src.y);
|
||||
glVertex2f(s->dst.x + s->dst.w, s->dst.y + s->dst.h);
|
||||
|
||||
glTexCoord2f(s->src.x, s->src.y);
|
||||
glVertex2f(s->dst.x, s->dst.y + s->dst.h);
|
||||
|
||||
s++;
|
||||
}
|
||||
glEnd();
|
||||
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||
}
|
||||
|
||||
SCount = 0;
|
||||
}
|
14
src/k3batch.h
Normal file
14
src/k3batch.h
Normal file
@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include"k3.h"
|
||||
#include<cglm/vec4.h>
|
||||
|
||||
struct k3RectF {
|
||||
float x;
|
||||
float y;
|
||||
float w;
|
||||
float h;
|
||||
};
|
||||
|
||||
void k3BatchAdd(struct k3Tex *tex, struct k3RectF src, struct k3RectF dst, float rot, vec4 color);
|
||||
void k3BatchFlush();
|
286
src/k3bloom.c
Normal file
286
src/k3bloom.c
Normal file
@ -0,0 +1,286 @@
|
||||
#include"k3bloom.h"
|
||||
|
||||
#include<stddef.h>
|
||||
#include"k3.h"
|
||||
#include<assert.h>
|
||||
#include"gl.h"
|
||||
|
||||
static struct k3GLSLP *tonemapper;
|
||||
|
||||
static struct k3GLSLP *minibloom1;
|
||||
static struct k3GLSLP *minibloom2;
|
||||
|
||||
int make_mb1() {
|
||||
struct k3GLSLV *v = !k3IsCore ? k3ShaderGLSLV(
|
||||
"uniform vec2 u_sz;" "\n"
|
||||
"varying vec2 v_uv;" "\n"
|
||||
"void main() {" "\n"
|
||||
" v_uv = gl_Vertex.xy * (1.0 + 1.0 / u_sz) * 0.5 + 0.5;""\n"
|
||||
" gl_Position = vec4(gl_Vertex.xy, 0, 1);" "\n"
|
||||
"}" "\n"
|
||||
, NULL) : k3ShaderGLSLV(
|
||||
"#version 330\n"
|
||||
"uniform vec2 u_sz;" "\n"
|
||||
"const vec4 positions[3] = vec4[3] (vec4(-1, -1, 0, 1), vec4(3, -1, 0, 1), vec4(-1, 3, 0, 1));\n"
|
||||
"out vec2 v_uv;" "\n"
|
||||
"void main() {" "\n"
|
||||
" v_uv = positions[gl_VertexID].xy * (1.0 + 1.0 / u_sz) * 0.5 + 0.5;""\n"
|
||||
" gl_Position = positions[gl_VertexID];" "\n"
|
||||
"}" "\n"
|
||||
, NULL);
|
||||
|
||||
if(!v) return 0;
|
||||
|
||||
struct k3GLSLF *f = !k3IsCore ? k3ShaderGLSLF(
|
||||
"#define THRESHOLD 0.7" "\n"
|
||||
"#define FACTOR 0.08" "\n"
|
||||
"uniform sampler2D u_tex;" "\n"
|
||||
"varying vec2 v_uv;" "\n"
|
||||
"vec3 get_col(vec2 uv) {" "\n"
|
||||
" vec3 col = texture2D(u_tex, uv).rgb;" "\n"
|
||||
" float luminance = col.r * 0.3086 + col.g * 0.6094 + col.b * 0.0820;" "\n"
|
||||
" if(luminance < THRESHOLD) col = vec3(0);" "\n"
|
||||
" return col * FACTOR;" "\n"
|
||||
"}" "\n"
|
||||
"void main() {" "\n"
|
||||
" vec3 c = vec3(0);" "\n"
|
||||
" c += 0.0020 * get_col(v_uv + vec2(-4.0 / 512.0, 0));" "\n"
|
||||
" c += 0.0060 * get_col(v_uv + vec2(-3.0 / 512.0, 0));" "\n"
|
||||
" c += 0.0606 * get_col(v_uv + vec2(-2.0 / 512.0, 0));" "\n"
|
||||
" c += 0.2417 * get_col(v_uv + vec2(-1.0 / 512.0, 0));" "\n"
|
||||
" c += 0.3829 * get_col(v_uv + vec2(+0.0 / 512.0, 0));" "\n"
|
||||
" c += 0.2417 * get_col(v_uv + vec2(+1.0 / 512.0, 0));" "\n"
|
||||
" c += 0.0606 * get_col(v_uv + vec2(+2.0 / 512.0, 0));" "\n"
|
||||
" c += 0.0060 * get_col(v_uv + vec2(+3.0 / 512.0, 0));" "\n"
|
||||
" c += 0.0020 * get_col(v_uv + vec2(+4.0 / 512.0, 0));" "\n"
|
||||
" gl_FragColor = vec4(c, 1);" "\n"
|
||||
"}" "\n"
|
||||
, NULL) : k3ShaderGLSLF(
|
||||
"#version 330\n"
|
||||
"#define THRESHOLD 0.7" "\n"
|
||||
"#define FACTOR 0.08" "\n"
|
||||
"uniform sampler2D u_tex;" "\n"
|
||||
"in vec2 v_uv;" "\n"
|
||||
"out vec4 fragcolor;" "\n"
|
||||
"vec3 get_col(vec2 uv) {" "\n"
|
||||
" vec3 col = texture2D(u_tex, uv).rgb;" "\n"
|
||||
" float luminance = col.r * 0.3086 + col.g * 0.6094 + col.b * 0.0820;" "\n"
|
||||
" if(luminance < THRESHOLD) col = vec3(0);" "\n"
|
||||
" return col * FACTOR;" "\n"
|
||||
"}" "\n"
|
||||
"void main() {" "\n"
|
||||
" vec3 c = vec3(0);" "\n"
|
||||
" c += 0.0020 * get_col(v_uv + vec2(-4.0 / 512.0, 0));" "\n"
|
||||
" c += 0.0060 * get_col(v_uv + vec2(-3.0 / 512.0, 0));" "\n"
|
||||
" c += 0.0606 * get_col(v_uv + vec2(-2.0 / 512.0, 0));" "\n"
|
||||
" c += 0.2417 * get_col(v_uv + vec2(-1.0 / 512.0, 0));" "\n"
|
||||
" c += 0.3829 * get_col(v_uv + vec2(+0.0 / 512.0, 0));" "\n"
|
||||
" c += 0.2417 * get_col(v_uv + vec2(+1.0 / 512.0, 0));" "\n"
|
||||
" c += 0.0606 * get_col(v_uv + vec2(+2.0 / 512.0, 0));" "\n"
|
||||
" c += 0.0060 * get_col(v_uv + vec2(+3.0 / 512.0, 0));" "\n"
|
||||
" c += 0.0020 * get_col(v_uv + vec2(+4.0 / 512.0, 0));" "\n"
|
||||
" fragcolor = vec4(c, 1);" "\n"
|
||||
"}" "\n"
|
||||
, NULL);
|
||||
|
||||
if(!f) return 0;
|
||||
|
||||
minibloom1 = k3ProgramGLSL(v, f, NULL);
|
||||
|
||||
if(!minibloom1) return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int make_mb2() {
|
||||
struct k3GLSLV *v = !k3IsCore ? k3ShaderGLSLV(
|
||||
"uniform vec2 u_sz;" "\n"
|
||||
"varying vec2 v_uv;" "\n"
|
||||
"void main() {" "\n"
|
||||
" v_uv = gl_Vertex.xy * (1.0 + 1.0 / u_sz) * 0.5 + 0.5;" "\n"
|
||||
" gl_Position = vec4(gl_Vertex.xy, 0, 1);" "\n"
|
||||
"}" "\n"
|
||||
, NULL) : k3ShaderGLSLV(
|
||||
"#version 330\n"
|
||||
"uniform vec2 u_sz;" "\n"
|
||||
"const vec4 positions[3] = vec4[3] (vec4(-1, -1, 0, 1), vec4(3, -1, 0, 1), vec4(-1, 3, 0, 1));\n"
|
||||
"out vec2 v_uv;" "\n"
|
||||
"void main() {" "\n"
|
||||
" v_uv = positions[gl_VertexID].xy * (1.0 + 1.0 / u_sz) * 0.5 + 0.5;" "\n"
|
||||
" gl_Position = positions[gl_VertexID];" "\n"
|
||||
"}" "\n"
|
||||
, NULL);
|
||||
|
||||
if(!v) return 0;
|
||||
|
||||
struct k3GLSLF *f = !k3IsCore ? k3ShaderGLSLF(
|
||||
"uniform sampler2D u_tex;" "\n"
|
||||
"varying vec2 v_uv;" "\n"
|
||||
"vec3 get_col(vec2 uv) {" "\n"
|
||||
" vec3 col = texture2D(u_tex, uv).rgb;" "\n"
|
||||
" return col;" "\n"
|
||||
"}" "\n"
|
||||
"void main() {" "\n"
|
||||
" vec3 c = vec3(0);" "\n"
|
||||
" c += 0.0020 * get_col(v_uv + vec2(0, -4.0 / 512.0));" "\n"
|
||||
" c += 0.0060 * get_col(v_uv + vec2(0, -3.0 / 512.0));" "\n"
|
||||
" c += 0.0606 * get_col(v_uv + vec2(0, -2.0 / 512.0));" "\n"
|
||||
" c += 0.2417 * get_col(v_uv + vec2(0, -1.0 / 512.0));" "\n"
|
||||
" c += 0.3829 * get_col(v_uv + vec2(0, +0.0 / 512.0));" "\n"
|
||||
" c += 0.2417 * get_col(v_uv + vec2(0, +1.0 / 512.0));" "\n"
|
||||
" c += 0.0606 * get_col(v_uv + vec2(0, +2.0 / 512.0));" "\n"
|
||||
" c += 0.0060 * get_col(v_uv + vec2(0, +3.0 / 512.0));" "\n"
|
||||
" c += 0.0020 * get_col(v_uv + vec2(0, +4.0 / 512.0));" "\n"
|
||||
" gl_FragColor = vec4(c, 1);" "\n"
|
||||
"}" "\n"
|
||||
, NULL) : k3ShaderGLSLF(
|
||||
"#version 330\n"
|
||||
"uniform sampler2D u_tex;" "\n"
|
||||
"in vec2 v_uv;" "\n"
|
||||
"out vec4 fragcolor;" "\n"
|
||||
"vec3 get_col(vec2 uv) {" "\n"
|
||||
" vec3 col = texture2D(u_tex, uv).rgb;" "\n"
|
||||
" return col;" "\n"
|
||||
"}" "\n"
|
||||
"void main() {" "\n"
|
||||
" vec3 c = vec3(0);" "\n"
|
||||
" c += 0.0020 * get_col(v_uv + vec2(0, -4.0 / 512.0));" "\n"
|
||||
" c += 0.0060 * get_col(v_uv + vec2(0, -3.0 / 512.0));" "\n"
|
||||
" c += 0.0606 * get_col(v_uv + vec2(0, -2.0 / 512.0));" "\n"
|
||||
" c += 0.2417 * get_col(v_uv + vec2(0, -1.0 / 512.0));" "\n"
|
||||
" c += 0.3829 * get_col(v_uv + vec2(0, +0.0 / 512.0));" "\n"
|
||||
" c += 0.2417 * get_col(v_uv + vec2(0, +1.0 / 512.0));" "\n"
|
||||
" c += 0.0606 * get_col(v_uv + vec2(0, +2.0 / 512.0));" "\n"
|
||||
" c += 0.0060 * get_col(v_uv + vec2(0, +3.0 / 512.0));" "\n"
|
||||
" c += 0.0020 * get_col(v_uv + vec2(0, +4.0 / 512.0));" "\n"
|
||||
" fragcolor = vec4(c, 1);" "\n"
|
||||
"}" "\n"
|
||||
, NULL);
|
||||
|
||||
if(!f) return 0;
|
||||
|
||||
minibloom2 = k3ProgramGLSL(v, f, NULL);
|
||||
|
||||
if(!minibloom2) return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int make_tonemapper() {
|
||||
struct k3GLSLV *v = !k3IsCore ? k3ShaderGLSLV(
|
||||
"varying vec2 v_uv;" "\n"
|
||||
"void main() {" "\n"
|
||||
" v_uv = gl_Vertex.xy * 0.5 + 0.5;" "\n"
|
||||
" gl_Position = vec4(gl_Vertex.xy, 0, 1);" "\n"
|
||||
"}" "\n"
|
||||
, NULL) : k3ShaderGLSLV(
|
||||
"#version 330\n"
|
||||
"const vec4 positions[3] = vec4[3] (vec4(-1, -1, 0, 1), vec4(3, -1, 0, 1), vec4(-1, 3, 0, 1));\n"
|
||||
"out vec2 v_uv;" "\n"
|
||||
"void main() {" "\n"
|
||||
" v_uv = positions[gl_VertexID].xy * 0.5 + 0.5;" "\n"
|
||||
" gl_Position = positions[gl_VertexID];" "\n"
|
||||
"}" "\n"
|
||||
, NULL);
|
||||
|
||||
if(!v) return 0;
|
||||
|
||||
struct k3GLSLF *f = k3ShaderGLSLF(
|
||||
"uniform sampler2D u_tex;" "\n"
|
||||
"varying vec2 v_uv;" "\n"
|
||||
"const vec3 WHITE = vec3(0.95045592705, 1.0, 1.08905775076);" "\n"
|
||||
"const mat3 RGB_2_XYZ = (mat3(" "\n"
|
||||
" 0.4124564, 0.2126729, 0.0193339," "\n"
|
||||
" 0.3575761, 0.7151522, 0.1191920," "\n"
|
||||
" 0.1804375, 0.0721750, 0.9503041" "\n"
|
||||
"));" "\n"
|
||||
"const mat3 XYZ_2_RGB = (mat3(" "\n"
|
||||
" 3.2404542,-0.9692660, 0.0556434," "\n"
|
||||
" -1.5371385, 1.8760108,-0.2040259," "\n"
|
||||
" -0.4985314, 0.0415560, 1.0572252" "\n"
|
||||
"));" "\n"
|
||||
"float XYZ_TO_LAB_F(float x) {"
|
||||
" return x > 0.00885645167 ? pow(x, 0.333333333) : 7.78703703704 * x + 0.13793103448;"
|
||||
"}"
|
||||
"vec3 XYZ_TO_LAB(vec3 xyz) {"
|
||||
" vec3 xyz_scaled = xyz / WHITE;"
|
||||
" xyz_scaled = vec3("
|
||||
" XYZ_TO_LAB_F(xyz_scaled.x),"
|
||||
" XYZ_TO_LAB_F(xyz_scaled.y),"
|
||||
" XYZ_TO_LAB_F(xyz_scaled.z)"
|
||||
" );"
|
||||
" return vec3("
|
||||
" (1.16 * xyz_scaled.y) - 0.16,"
|
||||
" 5.0 * (xyz_scaled.x - xyz_scaled.y),"
|
||||
" 2.0 * (xyz_scaled.y - xyz_scaled.z)"
|
||||
" );"
|
||||
"}"
|
||||
"float LAB_TO_XYZ_F(float x) {"
|
||||
" return (x > 0.206897) ? x * x * x : (0.12841854934 * (x - 0.137931034));"
|
||||
"}"
|
||||
"vec3 LAB_TO_XYZ(vec3 Lab) {"
|
||||
" float w = (Lab.x + 0.16) / 1.16;"
|
||||
" return WHITE * vec3("
|
||||
" LAB_TO_XYZ_F(w + Lab.y / 5.0),"
|
||||
" LAB_TO_XYZ_F(w),"
|
||||
" LAB_TO_XYZ_F(w - Lab.z / 2.0)"
|
||||
" );"
|
||||
"}"
|
||||
"vec3 toner(vec3 col, float whitepoint, float saturation) {" "\n"
|
||||
" vec3 xyz = RGB_2_XYZ * col;" "\n"
|
||||
" vec3 lab = XYZ_TO_LAB(xyz);" "\n"
|
||||
" lab.yz *= saturation;" "\n"
|
||||
" float n = lab.x * (1.0 + (lab.x / (whitepoint * whitepoint)));" "\n"
|
||||
" lab.x = n / (1.0 + lab.x);" "\n"
|
||||
" xyz = LAB_TO_XYZ(lab);" "\n"
|
||||
" return XYZ_2_RGB * xyz;" "\n"
|
||||
"}" "\n"
|
||||
"vec3 get_col(vec2 uv) {" "\n"
|
||||
" vec3 col = texture2D(u_tex, uv).rgb;" "\n"
|
||||
" col = toner(col, 0.80, 1.5);" "\n"
|
||||
" return col;" "\n"
|
||||
"}" "\n"
|
||||
"void main() {" "\n"
|
||||
" gl_FragColor = vec4(get_col(v_uv), 1);" "\n"
|
||||
"}" "\n"
|
||||
, NULL);
|
||||
|
||||
if(!f) return 0;
|
||||
|
||||
tonemapper = k3ProgramGLSL(v, f, NULL);
|
||||
|
||||
if(!tonemapper) return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int k3BloomInit() {
|
||||
if(!k3IsCore && !GLAD_GL_ARB_shading_language_100) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!make_mb1()) return 0;
|
||||
if(!make_mb2()) return 0;
|
||||
if(!make_tonemapper()) return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int k3Bloom(struct k3Offscreen *a, struct k3Offscreen *b) {
|
||||
if(!minibloom1) return 0;
|
||||
if(!minibloom2) return 0;
|
||||
|
||||
assert(b);
|
||||
|
||||
k3BeginOffscreen(b);
|
||||
k3BlitToScreenEffect(a, false, k3_GLSL, minibloom1, NULL);
|
||||
k3EndOffscreen(b);
|
||||
|
||||
k3BlitToScreenEffect(b, true, k3_GLSL, minibloom2, NULL);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct k3GLSLP *k3ToneMapper() {
|
||||
return tonemapper;
|
||||
}
|
8
src/k3bloom.h
Normal file
8
src/k3bloom.h
Normal file
@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
struct k3Offscreen;
|
||||
|
||||
int k3BloomInit();
|
||||
int k3Bloom(struct k3Offscreen *a, struct k3Offscreen *b);
|
||||
|
||||
struct k3GLSLP *k3ToneMapper();
|
150
src/k3font.c
Normal file
150
src/k3font.c
Normal file
@ -0,0 +1,150 @@
|
||||
#include"k3font.h"
|
||||
|
||||
#include"k3batch.h"
|
||||
#include<string.h>
|
||||
#include"gl.h"
|
||||
|
||||
struct k3Font *k3FontCreate() {
|
||||
struct k3Font *ret = calloc(sizeof(*ret), 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cmpglyph(const void *a, const void *b) {
|
||||
return *(const uint32_t*) a - *(const uint32_t*) b;
|
||||
}
|
||||
|
||||
int k3FontLoad(struct k3Font *this, const uint8_t *buf, size_t len, k3FontTexLoader texldr) {
|
||||
if(*(uint32_t*) buf != 0x03464D42) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const uint8_t *end = buf + len;
|
||||
|
||||
buf += 4;
|
||||
|
||||
uint16_t pages = 0;
|
||||
|
||||
while(buf + 5 < end) {
|
||||
uint8_t blockType = *buf;
|
||||
uint32_t blockSize = *(uint32_t*) (buf + 1);
|
||||
buf += 5;
|
||||
|
||||
if(blockType == 1) { //Info block
|
||||
buf += 14;
|
||||
while(*buf) buf++;
|
||||
buf++;
|
||||
} else if(blockType == 2) { //Common block
|
||||
this->lineScale = 1.f / *(uint16_t*) buf;
|
||||
buf += 2;
|
||||
this->baseline = *(uint16_t*) buf;
|
||||
buf += 2;
|
||||
this->texW = *(uint16_t*) buf;
|
||||
buf += 2;
|
||||
this->texH = *(uint16_t*) buf;
|
||||
buf += 2;
|
||||
pages = *(uint16_t*) buf;
|
||||
buf += 7;
|
||||
} else if(blockType == 3) { //Pages block
|
||||
if(pages == 0) return 0;
|
||||
|
||||
this->pageCount = pages;
|
||||
this->pages = malloc(sizeof(*this->pages) * this->pageCount);
|
||||
|
||||
for(size_t i = 0; i < this->pageCount; i++) {
|
||||
this->pages[i] = texldr(this, buf);
|
||||
buf += strlen(buf) + 1;
|
||||
}
|
||||
} else if(blockType == 4) { //Chars block
|
||||
size_t num = blockSize / 20;
|
||||
|
||||
this->glyphs = calloc(sizeof(*this->glyphs), this->glyphCount = num);
|
||||
|
||||
memcpy(this->glyphs, buf, num * 20);
|
||||
|
||||
qsort(this->glyphs, num, sizeof(*this->glyphs), cmpglyph);
|
||||
|
||||
buf += blockSize;
|
||||
} else if(blockType == 5) { //Kerning block
|
||||
// Ignore kerning for now
|
||||
buf += blockSize;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static uint32_t read_utf8(const char **txt_) {
|
||||
const uint8_t **txt = (void*) txt_;
|
||||
if(**txt == 0) {
|
||||
return 0;
|
||||
} else if(**txt < 0x80) {
|
||||
return *(*txt)++;
|
||||
} else if(**txt < 0xE0) {
|
||||
uint32_t ret = ((*(*txt)++) & 0x1F) << 6;
|
||||
ret |= (*(*txt)++) & 0x3F;
|
||||
return ret;
|
||||
} else if(**txt < 0xF0) {
|
||||
uint32_t ret = ((*(*txt)++) & 0x0F) << 12;
|
||||
ret |= ((*(*txt)++) & 0x3F) << 6;
|
||||
ret |= (*(*txt)++) & 0x3F;
|
||||
return ret;
|
||||
} else {
|
||||
uint32_t ret = ((*(*txt)++) & 0x07) << 18;
|
||||
ret |= ((*(*txt)++) & 0x3F) << 12;
|
||||
ret |= ((*(*txt)++) & 0x3F) << 6;
|
||||
ret |= (*(*txt)++) & 0x3F;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
void k3FontSz(struct k3Font *this, float sz, const char *txt, struct k3RectF *ret) {
|
||||
float x = 0, y = 0;
|
||||
while(1) {
|
||||
uint32_t cp = read_utf8(&txt);
|
||||
|
||||
if(!cp) break;
|
||||
|
||||
struct k3FontGlyph *g = k3FontGetGlyph(this, cp);
|
||||
|
||||
if(!g) continue;
|
||||
|
||||
x += g->xadvance * this->lineScale * sz;
|
||||
}
|
||||
ret->w = x;
|
||||
}
|
||||
void k3FontDraw(struct k3Font *this, float xStart, float yStart, float sz, const char *txt, vec4 color) {
|
||||
float x = xStart, y = yStart;
|
||||
while(1) {
|
||||
uint32_t cp = read_utf8(&txt);
|
||||
|
||||
if(!cp) break;
|
||||
|
||||
if(cp == 10) {
|
||||
x = xStart;
|
||||
y -= sz;
|
||||
}
|
||||
|
||||
struct k3FontGlyph *g = k3FontGetGlyph(this, cp);
|
||||
|
||||
if(!g) continue;
|
||||
|
||||
struct k3Tex *tex = this->pages[g->page];
|
||||
size_t texW = this->texW;
|
||||
size_t texH = this->texH;
|
||||
k3BatchAdd(tex,
|
||||
(struct k3RectF) {(float) g->x / texW, (float) g->y / texH, (float) g->width / texW, (float) g->height / texH},
|
||||
(struct k3RectF) {
|
||||
x + g->xoffset * this->lineScale * sz,
|
||||
y + ((-g->height - g->yoffset) * this->lineScale + 1) * sz,
|
||||
g->width * this->lineScale * sz,
|
||||
g->height * this->lineScale * sz
|
||||
}, 0, color);
|
||||
|
||||
x += g->xadvance * this->lineScale * sz;
|
||||
}
|
||||
k3BatchFlush();
|
||||
}
|
||||
|
||||
struct k3FontGlyph *k3FontGetGlyph(struct k3Font *this, uint32_t cp) {
|
||||
return bsearch(&cp, this->glyphs, this->glyphCount, sizeof(*this->glyphs), cmpglyph);
|
||||
}
|
77
src/k3font.h
Normal file
77
src/k3font.h
Normal file
@ -0,0 +1,77 @@
|
||||
#pragma once
|
||||
|
||||
#include"k3.h"
|
||||
#include"k3batch.h"
|
||||
#include<string.h>
|
||||
|
||||
struct k3FontGlyph {
|
||||
uint32_t cp;
|
||||
uint16_t x;
|
||||
uint16_t y;
|
||||
uint16_t width;
|
||||
uint16_t height;
|
||||
int16_t xoffset;
|
||||
int16_t yoffset;
|
||||
uint16_t xadvance;
|
||||
uint8_t page;
|
||||
uint8_t chnl;
|
||||
};
|
||||
|
||||
struct k3Font {
|
||||
void *ud;
|
||||
|
||||
float lineScale;
|
||||
|
||||
uint16_t baseline;
|
||||
|
||||
uint16_t texW, texH;
|
||||
|
||||
size_t glyphCount;
|
||||
struct k3FontGlyph *glyphs;
|
||||
|
||||
size_t pageCount;
|
||||
struct k3Tex **pages;
|
||||
};
|
||||
|
||||
typedef struct k3Tex*(*k3FontTexLoader)(struct k3Font*, const char *name);
|
||||
|
||||
struct k3Font *k3FontCreate();
|
||||
int k3FontLoad(struct k3Font*, const uint8_t *buf, size_t len, k3FontTexLoader);
|
||||
|
||||
void k3FontSz(struct k3Font*, float sz, const char *txt, struct k3RectF *ret);
|
||||
void k3FontDraw(struct k3Font*, float x, float y, float sz, const char *txt, vec4 color);
|
||||
|
||||
struct k3FontGlyph *k3FontGetGlyph(struct k3Font*, uint32_t cp);
|
||||
|
||||
static inline int k3UTF8Encode(uint32_t cp, uint8_t ret[static 4]) {
|
||||
if(cp < 0x80) {
|
||||
ret[0] = cp;
|
||||
return 1;
|
||||
} else if(cp < 0x800) {
|
||||
ret[0] = 192 | (cp >> 6);
|
||||
ret[1] = 128 | (cp & 63);
|
||||
return 2;
|
||||
} else if(cp < 0x10000) {
|
||||
ret[0] = 224 | (cp >> 12);
|
||||
ret[1] = 128 | ((cp >> 6) & 63);
|
||||
ret[2] = 128 | (cp & 63);
|
||||
return 3;
|
||||
} else if(cp < 0x110000) {
|
||||
ret[0] = 240 | (cp >> 18);
|
||||
ret[1] = 128 | ((cp >> 12) & 63);
|
||||
ret[2] = 128 | ((cp >> 6) & 63);
|
||||
ret[3] = 128 | (cp & 63);
|
||||
return 4;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline const char *k3UTF8LastCodepointZ(const char *txt) {
|
||||
size_t len = strlen(txt);
|
||||
while(len--) {
|
||||
if((txt[len] & 0xC0) != 0x80) {
|
||||
return &txt[len];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
352
src/k3menu.c
Normal file
352
src/k3menu.c
Normal file
@ -0,0 +1,352 @@
|
||||
#include"k3menu.h"
|
||||
|
||||
#include<string.h>
|
||||
#include<stdio.h>
|
||||
#include<GLFW/glfw3.h>
|
||||
|
||||
void k3MenuSetBounds_(struct k3MObj *this, int16_t x, int16_t y, int16_t w, int16_t h) {
|
||||
this->x = x;
|
||||
this->y = y;
|
||||
this->w = w;
|
||||
this->h = h;
|
||||
}
|
||||
|
||||
static bool event_send_nonrecur(struct k3MEvent *ev) {
|
||||
bool handled = false;
|
||||
for(size_t i = 0; i < ev->target->handlerCount; i++) {
|
||||
struct k3MEventHandler *h = &ev->target->handlers[i];
|
||||
|
||||
if(h->code == ev->code || h->code == k3M_EVENT_ALL) {
|
||||
if(h->callback(ev, h->ud)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
int k3MRegisterEventHandler_(struct k3MObj *obj, uint16_t evcode, k3MEventHandlerFunc callback, uint8_t *ud, size_t udSize) {
|
||||
if(ud && udSize > k3M_USERDATA_SIZE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
obj->handlers = realloc(obj->handlers, sizeof(*obj->handlers) * ++obj->handlerCount);
|
||||
|
||||
obj->handlers[obj->handlerCount - 1].code = evcode;
|
||||
obj->handlers[obj->handlerCount - 1].callback = callback;
|
||||
if(ud) {
|
||||
memcpy(obj->handlers[obj->handlerCount - 1].ud, ud, udSize);
|
||||
}
|
||||
}
|
||||
|
||||
bool k3MEventSend(struct k3MEvent *ev) {
|
||||
while(!event_send_nonrecur(ev)) {
|
||||
if(ev->kind == k3M_EVENTKIND_DIRECT) {
|
||||
return false;
|
||||
} else if(ev->kind == k3M_EVENTKIND_BUBBLE) {
|
||||
ev->target = ev->target->parent;
|
||||
|
||||
if(ev->target == ev->original || !ev->target) {
|
||||
return false;
|
||||
}
|
||||
} else if(ev->kind == k3M_EVENTKIND_CAPTURE) {
|
||||
struct k3MObj *parent = ev->target;
|
||||
|
||||
for(size_t i = 0; i < parent->childCount; i++) {
|
||||
if(!parent->children[i]->invisible) {
|
||||
ev->target = parent->children[i];
|
||||
|
||||
if(k3MEventSend(ev)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool label_draw(struct k3MEvent *ev, uint8_t *ud) {
|
||||
struct k3MLabel *this = (void*) ev->target;
|
||||
|
||||
if(this->txt) {
|
||||
k3FontDraw(this->font, this->x, this->y, this->sz, this->txt, (vec4) {1, 1, 1, 1});
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
struct k3MLabel *k3MLabel(struct k3Font *font, float sz, const char *txt) {
|
||||
struct k3MLabel *ret = calloc(1, sizeof(*ret));
|
||||
ret->font = font;
|
||||
ret->sz = sz;
|
||||
ret->txt = txt;
|
||||
|
||||
k3MRegisterEventHandler(ret, k3M_EVENT_DRAW, label_draw, NULL, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int k3MRemoveChild(struct k3MObj *parent, struct k3MObj *child) {
|
||||
for(size_t i = 0; i < parent->childCount; i++) {
|
||||
if(parent->children[i] == child) {
|
||||
memcpy(&parent->children[i], &parent->children[i + 1], sizeof(*parent->children) * (parent->childCount - i - 1));
|
||||
|
||||
parent->childCount--;
|
||||
|
||||
child->parent = NULL;
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void k3MAddChild(struct k3MObj *parent, struct k3MObj *child) {
|
||||
if(child->parent) {
|
||||
k3MRemoveChild(child->parent, child);
|
||||
}
|
||||
|
||||
parent->children = realloc(parent->children, sizeof(*parent->children) * (++parent->childCount));
|
||||
parent->children[parent->childCount - 1] = child;
|
||||
|
||||
child->parent = parent;
|
||||
}
|
||||
|
||||
/*static struct k3Menu *k3ScreenFuncMouse(struct k3Menu *_, int16_t x, int16_t y, int ev) {
|
||||
struct k3Screen *this = (void*) _;
|
||||
|
||||
if(ev == k3_MENU_MOUSE_MOVE) {
|
||||
struct k3Menu *newHovered = k3ContainerFuncMouse(_, x, y, k3_MENU_MOUSE_TEST);
|
||||
if(this->hovered != newHovered) {
|
||||
if(this->hovered && this->hovered->funcmouse) {
|
||||
this->hovered->funcmouse(this->hovered, x, y, k3_MENU_MOUSE_OUT);
|
||||
}
|
||||
|
||||
this->hovered = newHovered;
|
||||
|
||||
if(this->hovered && this->hovered->funcmouse) {
|
||||
this->hovered->funcmouse(this->hovered, x, y, k3_MENU_MOUSE_IN);
|
||||
}
|
||||
} else {
|
||||
if(this->hovered && this->hovered->funcmouse) {
|
||||
return this->hovered->funcmouse(this->hovered, x, y, k3_MENU_MOUSE_MOVE);
|
||||
}
|
||||
}
|
||||
} else if(this->hovered && this->hovered->funcmouse) {
|
||||
struct k3Menu *ret = this->hovered->funcmouse(this->hovered, x, y, ev);
|
||||
this->keyboardFocus = ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void k3ScreenFuncKey(struct k3Menu *_, int key, int action, int modifiers) {
|
||||
struct k3Screen *this = (void*) _;
|
||||
|
||||
if(this->keyboardFocus && this->keyboardFocus->funckey) {
|
||||
this->keyboardFocus->funckey(this->keyboardFocus, key, action, modifiers);
|
||||
}
|
||||
}
|
||||
|
||||
static void k3ScreenFuncChar(struct k3Menu *_, uint32_t codepoint) {
|
||||
struct k3Screen *this = (void*) _;
|
||||
|
||||
if(this->keyboardFocus && this->keyboardFocus->funcchar) {
|
||||
this->keyboardFocus->funcchar(this->keyboardFocus, codepoint);
|
||||
}
|
||||
}*/
|
||||
|
||||
static bool screen_ev(struct k3MEvent *ev, uint8_t *ud) {
|
||||
struct k3MScreen *this = (void*) ev->target;
|
||||
|
||||
if(ev->code == k3M_EVENT_MOUSE_PRESS || ev->code == k3M_EVENT_MOUSE_RELEASE || ev->code == k3M_EVENT_MOUSE_MOTION) {
|
||||
struct k3MObj *innermost = (void*) this;
|
||||
|
||||
while(innermost->childCount != 0) {
|
||||
|
||||
bool foundInner = false;
|
||||
|
||||
for(intmax_t i = innermost->childCount - 1; i >= 0; i--) {
|
||||
|
||||
struct k3MObj *child = innermost->children[i];
|
||||
|
||||
if(!child->invisible && ev->mouse.x >= child->x && ev->mouse.x < child->x + child->w && ev->mouse.y >= child->y && ev->mouse.y < child->y + child->h) {
|
||||
|
||||
innermost = child;
|
||||
foundInner = true;
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(!foundInner) {
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(innermost != (void*) this) {
|
||||
|
||||
if(ev->code == k3M_EVENT_MOUSE_PRESS) {
|
||||
this->keyboardFocus = innermost;
|
||||
}
|
||||
|
||||
ev->kind = k3M_EVENTKIND_BUBBLE;
|
||||
ev->target = innermost;
|
||||
k3MEventSend(ev);
|
||||
|
||||
if(ev->code == k3M_EVENT_MOUSE_RELEASE) {
|
||||
ev->code = k3M_EVENT_MOUSE_CLICK;
|
||||
|
||||
ev->kind = k3M_EVENTKIND_DIRECT;
|
||||
ev->target = innermost;
|
||||
k3MEventSend(ev);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
} else if(ev->code == k3M_EVENT_KEY_PRESS || ev->code == k3M_EVENT_KEY_RELEASE || ev->code == k3M_EVENT_INPUT) {
|
||||
|
||||
if(this->keyboardFocus) {
|
||||
ev->kind = k3M_EVENTKIND_BUBBLE;
|
||||
ev->target = (void*) this->keyboardFocus;
|
||||
k3MEventSend(ev);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
ev->kind = k3M_EVENTKIND_CAPTURE;
|
||||
for(intmax_t i = this->childCount - 1; i >= 0; i--) {
|
||||
if(!this->children[i]->invisible) {
|
||||
ev->target = this->children[i];
|
||||
if(k3MEventSend(ev)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
struct k3MScreen *k3MScreen() {
|
||||
struct k3MScreen *ret = calloc(1, sizeof(*ret));
|
||||
|
||||
k3MRegisterEventHandler(ret, k3M_EVENT_ALL, screen_ev, NULL, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool textbutton_draw(struct k3MEvent *ev, uint8_t *ud) {
|
||||
struct k3MTextButton *this = (void*) ev->target;
|
||||
|
||||
if(this->txt) {
|
||||
k3BatchAdd(NULL, (struct k3RectF) {}, (struct k3RectF) {
|
||||
this->x, this->y,
|
||||
this->w, this->h
|
||||
}, 0, (vec4) {1, 1, 1, 0.2 + 0.1 * this->hovered});
|
||||
|
||||
struct k3RectF txtsz;
|
||||
k3FontSz(this->font, this->sz, this->txt, &txtsz);
|
||||
|
||||
k3FontDraw(this->font, this->x + this->w / 2 - txtsz.w / 2, this->y, this->sz, this->txt, (vec4) {
|
||||
1 - 0.8 * this->disabled, 1 - 0.8 * this->disabled, 1 - 0.8 * this->disabled, 1});
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
struct k3MTextButton *k3MTextButton(struct k3Font *font, float sz, const char *txt) {
|
||||
struct k3MTextButton *ret = calloc(1, sizeof(*ret));
|
||||
|
||||
ret->font = font;
|
||||
ret->sz = sz;
|
||||
ret->txt = txt;
|
||||
|
||||
k3MRegisterEventHandler(ret, k3M_EVENT_DRAW, textbutton_draw, NULL, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool textinput_draw(struct k3MEvent *ev, uint8_t *ud) {
|
||||
struct k3MTextInput *this = (void*) ev->target;
|
||||
|
||||
if(this->txt) {
|
||||
k3BatchAdd(NULL, (struct k3RectF) {}, (struct k3RectF) {
|
||||
this->x, this->y,
|
||||
this->w, this->h
|
||||
}, 0, (vec4) {1, 1, 1, 0.2});
|
||||
|
||||
int isPlaceholder = strlen(this->txt) == 0;
|
||||
const char *txt = isPlaceholder ? this->placeholder : this->txt;
|
||||
|
||||
struct k3RectF txtsz;
|
||||
k3FontSz(this->font, this->sz, txt, &txtsz);
|
||||
|
||||
k3FontDraw(this->font, this->x, this->y, this->sz, txt, (vec4) {1 - 0.5 * isPlaceholder, 1 - 0.5 * isPlaceholder, 1 - 0.5 * isPlaceholder, 1});
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
static bool textinput_key(struct k3MEvent *ev, uint8_t *ud) {
|
||||
struct k3MTextInput *this = (void*) ev->target;
|
||||
|
||||
if(ev->key.num == GLFW_KEY_BACKSPACE && ev->code != k3M_EVENT_KEY_RELEASE) {
|
||||
char *last = k3UTF8LastCodepointZ(this->txt);
|
||||
if(last) {
|
||||
*last = 0;
|
||||
}
|
||||
} else if(ev->key.num == GLFW_KEY_ENTER && ev->code == k3M_EVENT_KEY_PRESS) {
|
||||
struct k3MEvent newev = {
|
||||
.code = k3M_EVENT_COMPLETE,
|
||||
.kind = k3M_EVENTKIND_DIRECT,
|
||||
|
||||
.original = (void*) this,
|
||||
.target = (void*) this,
|
||||
};
|
||||
|
||||
k3MEventSend(&newev);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
static bool textinput_char(struct k3MEvent *ev, uint8_t *ud) {
|
||||
struct k3MTextInput *this = (void*) ev->target;
|
||||
|
||||
size_t len = strlen(this->txt);
|
||||
|
||||
this->txt = realloc(this->txt, len + 5);
|
||||
len += k3UTF8Encode(ev->input.code, this->txt + len);
|
||||
this->txt[len] = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
struct k3MTextInput *k3MTextInput(struct k3Font *font, float sz, const char *placeholder, const char *txt) {
|
||||
struct k3MTextInput *ret = calloc(1, sizeof(*ret));
|
||||
|
||||
ret->font = font;
|
||||
ret->sz = sz;
|
||||
ret->placeholder = placeholder ? placeholder : "";
|
||||
ret->txt = strdup(txt ? txt : "");
|
||||
|
||||
k3MRegisterEventHandler(ret, k3M_EVENT_DRAW, textinput_draw, NULL, 0);
|
||||
k3MRegisterEventHandler(ret, k3M_EVENT_KEY_PRESS, textinput_key, NULL, 0);
|
||||
k3MRegisterEventHandler(ret, k3M_EVENT_KEY_RELEASE, textinput_key, NULL, 0);
|
||||
k3MRegisterEventHandler(ret, k3M_EVENT_INPUT, textinput_char, NULL, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct k3MObj *k3MObj() {
|
||||
struct k3MObj *ret = calloc(1, sizeof(*ret));
|
||||
return ret;
|
||||
}
|
127
src/k3menu.h
Normal file
127
src/k3menu.h
Normal file
@ -0,0 +1,127 @@
|
||||
#pragma once
|
||||
|
||||
#include<stdint.h>
|
||||
#include<stdlib.h>
|
||||
#include<stdbool.h>
|
||||
#include"k3font.h"
|
||||
|
||||
struct k3MObj;
|
||||
|
||||
#define k3M_EVENT_MOUSE_ENTER 0
|
||||
#define k3M_EVENT_MOUSE_MOTION 1
|
||||
#define k3M_EVENT_MOUSE_LEAVE 2
|
||||
#define k3M_EVENT_MOUSE_PRESS 3
|
||||
#define k3M_EVENT_MOUSE_RELEASE 4
|
||||
#define k3M_EVENT_MOUSE_CLICK 5
|
||||
#define k3M_EVENT_KEY_PRESS 6
|
||||
#define k3M_EVENT_KEY_RELEASE 7
|
||||
#define k3M_EVENT_INPUT 8
|
||||
#define k3M_EVENT_DRAW 9
|
||||
#define k3M_EVENT_COMPLETE 10
|
||||
#define k3M_EVENT_ALL 11
|
||||
|
||||
#define k3M_MOUSE_BUTTON_0 0
|
||||
#define k3M_MOUSE_BUTTON_1 1
|
||||
#define k3M_MOUSE_BUTTON_2 2
|
||||
|
||||
#define k3M_EVENTKIND_DIRECT 0
|
||||
#define k3M_EVENTKIND_CAPTURE 1
|
||||
#define k3M_EVENTKIND_BUBBLE 2
|
||||
|
||||
#define k3M_USERDATA_SIZE 16
|
||||
|
||||
struct k3MEvent {
|
||||
uint16_t code;
|
||||
|
||||
uint8_t kind;
|
||||
|
||||
struct k3MObj *original;
|
||||
struct k3MObj *target;
|
||||
|
||||
union {
|
||||
struct {
|
||||
int button;
|
||||
int16_t x;
|
||||
int16_t y;
|
||||
} mouse;
|
||||
struct {
|
||||
uint32_t num;
|
||||
} key;
|
||||
struct {
|
||||
uint32_t code;
|
||||
} input;
|
||||
};
|
||||
};
|
||||
|
||||
typedef bool(*k3MEventHandlerFunc)(struct k3MEvent*, uint8_t *ud);
|
||||
|
||||
typedef struct k3MEventHandler {
|
||||
uint8_t ud[k3M_USERDATA_SIZE];
|
||||
k3MEventHandlerFunc callback;
|
||||
uint16_t code;
|
||||
} k3MEventHandler;
|
||||
|
||||
struct k3MObj {
|
||||
struct k3MObj *parent;
|
||||
|
||||
size_t childCount;
|
||||
struct k3MObj **children;
|
||||
|
||||
int16_t x;
|
||||
int16_t y;
|
||||
int16_t w;
|
||||
int16_t h;
|
||||
|
||||
bool invisible, hovered, disabled;
|
||||
|
||||
k3MEventHandler *handlers;
|
||||
size_t handlerCount;
|
||||
};
|
||||
|
||||
#define k3MenuSetBounds(a, x, y, w, h) k3MenuSetBounds_((struct k3MObj*) (a), (x), (y), (w), (h))
|
||||
void k3MenuSetBounds_(struct k3MObj *this, int16_t x, int16_t y, int16_t w, int16_t h);
|
||||
|
||||
#define k3MRegisterEventHandler(a, c, cb, ud, udsz) k3MRegisterEventHandler_((struct k3MObj*) (a), (c), (cb), (ud), (udsz))
|
||||
int k3MRegisterEventHandler_(struct k3MObj *obj, uint16_t evcode, k3MEventHandlerFunc callback, uint8_t *ud, size_t udSize);
|
||||
|
||||
bool k3MEventSend(struct k3MEvent *ev);
|
||||
|
||||
int k3MRemoveChild(struct k3MObj *parent, struct k3MObj *child);
|
||||
void k3MAddChild(struct k3MObj *parent, struct k3MObj *child);
|
||||
|
||||
struct k3MLabel {
|
||||
struct k3MObj;
|
||||
|
||||
struct k3Font *font;
|
||||
float sz;
|
||||
char *txt;
|
||||
};
|
||||
struct k3MLabel *k3MLabel(struct k3Font *font, float sz, const char *txt);
|
||||
|
||||
struct k3MScreen {
|
||||
struct k3MObj;
|
||||
|
||||
struct k3MObj *keyboardFocus;
|
||||
};
|
||||
struct k3MScreen *k3MScreen();
|
||||
|
||||
struct k3MTextButton {
|
||||
struct k3MObj;
|
||||
|
||||
struct k3Font *font;
|
||||
float sz;
|
||||
char *txt;
|
||||
};
|
||||
struct k3MTextButton *k3MTextButton(struct k3Font *font, float sz, const char *txt);
|
||||
|
||||
struct k3MTextInput {
|
||||
struct k3MObj;
|
||||
|
||||
struct k3Font *font;
|
||||
float sz;
|
||||
|
||||
char *placeholder;
|
||||
|
||||
char *txt;
|
||||
};
|
||||
struct k3MTextInput *k3MTextInput(struct k3Font *font, float sz, const char *placeholder, const char *txt);
|
150
src/k3water.c
Normal file
150
src/k3water.c
Normal file
@ -0,0 +1,150 @@
|
||||
#include"k3water.h"
|
||||
|
||||
#include<string.h>
|
||||
#include<stdio.h>
|
||||
|
||||
struct k3Water *k3WaterCreate(float w, float h, size_t subdivisions, struct k3Mat *mat) {
|
||||
size_t edgesubdiv = 2 + subdivisions;
|
||||
|
||||
size_t vertices = edgesubdiv * edgesubdiv;
|
||||
|
||||
struct k3Water *ret = malloc(sizeof(*ret));
|
||||
|
||||
ret->w = w;
|
||||
ret->h = h;
|
||||
|
||||
for(int f = 0; f < k3_WATER_FRAMES; f++) {
|
||||
ret->frames[f] = malloc(sizeof(vec3) * vertices);
|
||||
}
|
||||
|
||||
ret->curFrame = 0;
|
||||
|
||||
ret->dx = w / (edgesubdiv - 1);
|
||||
ret->dy = h / (edgesubdiv - 1);
|
||||
|
||||
ret->ptsPerEdge = edgesubdiv;
|
||||
|
||||
for(int z = 0; z < edgesubdiv; z++) {
|
||||
for(int x = 0; x < edgesubdiv; x++) {
|
||||
ret->frames[0][z * edgesubdiv + x][0] = x * w / (edgesubdiv - 1) - w / 2;
|
||||
ret->frames[0][z * edgesubdiv + x][1] = 0;
|
||||
ret->frames[0][z * edgesubdiv + x][2] = z * h / (edgesubdiv - 1) - h / 2;
|
||||
}
|
||||
}
|
||||
memcpy(ret->frames[1], ret->frames[0], sizeof(vec3) * vertices);
|
||||
memcpy(ret->frames[2], ret->frames[0], sizeof(vec3) * vertices);
|
||||
|
||||
size_t indices = (1 + subdivisions) * (1 + subdivisions) * 6;
|
||||
uint16_t *inds = malloc(sizeof(*inds) * indices);
|
||||
|
||||
for(int z = 0; z <= subdivisions; z++) {
|
||||
for(int x = 0; x <= subdivisions; x++) {
|
||||
inds[6 * (z * (subdivisions + 1) + x) + 0] = (z * edgesubdiv + x) + 0;
|
||||
inds[6 * (z * (subdivisions + 1) + x) + 1] = (z * edgesubdiv + x) + edgesubdiv;
|
||||
inds[6 * (z * (subdivisions + 1) + x) + 2] = (z * edgesubdiv + x) + edgesubdiv + 1;
|
||||
inds[6 * (z * (subdivisions + 1) + x) + 3] = (z * edgesubdiv + x) + 0;
|
||||
inds[6 * (z * (subdivisions + 1) + x) + 4] = (z * edgesubdiv + x) + edgesubdiv + 1;
|
||||
inds[6 * (z * (subdivisions + 1) + x) + 5] = (z * edgesubdiv + x) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *norms = alloca(ret->ptsPerEdge * ret->ptsPerEdge * sizeof(*norms) * 3);
|
||||
|
||||
ret->mdl = k3MdlCreate(vertices, indices, 0, ret->frames[0], norms, NULL, NULL, NULL, NULL, inds, NULL, NULL);
|
||||
|
||||
k3MdlAddMesh(ret->mdl, mat, 0, indices);
|
||||
|
||||
free(inds);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void k3WaterSimSubStep(struct k3Water *this, float dt, float C, float mu) {
|
||||
int prevPrevFrame = (this->curFrame + (k3_WATER_FRAMES - 1)) % k3_WATER_FRAMES;
|
||||
int prevFrame = this->curFrame;
|
||||
this->curFrame = (this->curFrame + 1) % k3_WATER_FRAMES;
|
||||
|
||||
vec3 *prevPrev = this->frames[prevPrevFrame];
|
||||
vec3 *prev = this->frames[prevFrame];
|
||||
vec3 *cur = this->frames[this->curFrame];
|
||||
|
||||
for(int z = 1; z < this->ptsPerEdge - 1; z++) {
|
||||
for(int x = 1; x < this->ptsPerEdge - 1; x++) {
|
||||
cur[z * this->ptsPerEdge + x][1] =
|
||||
+ 4 * prev[z * this->ptsPerEdge + x][1] / (2 + mu * dt)
|
||||
- prevPrev[z * this->ptsPerEdge + x][1] * (2 - mu * dt) / (2 + mu * dt)
|
||||
+ 2 * C * C * dt * dt * (
|
||||
(prev[z * this->ptsPerEdge + x + 1][1] - 2 * prev[z * this->ptsPerEdge + x][1] + prev[z * this->ptsPerEdge + x - 1][1]) / (this->dx * this->dx) +
|
||||
(prev[(z + 1) * this->ptsPerEdge + x][1] - 2 * prev[z * this->ptsPerEdge + x][1] + prev[(z - 1) * this->ptsPerEdge + x][1]) / (this->dy * this->dy)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for(int x = 1; x < this->ptsPerEdge - 1; x++) {
|
||||
cur[0 * this->ptsPerEdge + x][1] = 0;
|
||||
cur[(this->ptsPerEdge - 1) * this->ptsPerEdge + x][1] = 0;
|
||||
}
|
||||
|
||||
for(int z = 0; z < this->ptsPerEdge; z++) {
|
||||
cur[z * this->ptsPerEdge + 0][1] = 0;
|
||||
cur[z * this->ptsPerEdge + this->ptsPerEdge - 1][1] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void k3WaterSimulate(struct k3Water *this, float dt, float C, float mu, int substeps) {
|
||||
for(int i = 0; i < substeps; i++) {
|
||||
k3WaterSimSubStep(this, dt / substeps, C, mu);
|
||||
}
|
||||
}
|
||||
|
||||
void k3WaterUpdate(struct k3Water *this) {
|
||||
k3MdlUpdatePos(this->mdl, this->frames[this->curFrame]);
|
||||
|
||||
typedef int8_t Nrm[3];
|
||||
|
||||
Nrm *nrm = alloca(this->ptsPerEdge * this->ptsPerEdge * sizeof(*nrm));
|
||||
|
||||
for(size_t i = 0; i < this->ptsPerEdge; i++) {
|
||||
nrm[i * this->ptsPerEdge + 0][0] = 0;
|
||||
nrm[i * this->ptsPerEdge + 0][1] = 1;
|
||||
nrm[i * this->ptsPerEdge + 0][2] = 0;
|
||||
|
||||
nrm[i * this->ptsPerEdge + this->ptsPerEdge - 1][0] = 0;
|
||||
nrm[i * this->ptsPerEdge + this->ptsPerEdge - 1][1] = 1;
|
||||
nrm[i * this->ptsPerEdge + this->ptsPerEdge - 1][2] = 0;
|
||||
|
||||
nrm[0 * this->ptsPerEdge + i][0] = 0;
|
||||
nrm[0 * this->ptsPerEdge + i][1] = 1;
|
||||
nrm[0 * this->ptsPerEdge + i][2] = 0;
|
||||
|
||||
nrm[(this->ptsPerEdge - 1) * this->ptsPerEdge + i][0] = 0;
|
||||
nrm[(this->ptsPerEdge - 1) * this->ptsPerEdge + i][1] = 1;
|
||||
nrm[(this->ptsPerEdge - 1) * this->ptsPerEdge + i][2] = 0;
|
||||
}
|
||||
|
||||
for(size_t z = 1; z < this->ptsPerEdge - 1; z++) {
|
||||
for(size_t x = 1; x < this->ptsPerEdge - 1; x++) {
|
||||
vec3 n = {
|
||||
(this->frames[this->curFrame][z * this->ptsPerEdge + x + 1][1] - this->frames[this->curFrame][z * this->ptsPerEdge + x - 1][1]) / 2,
|
||||
1,
|
||||
(this->frames[this->curFrame][(z + 1) * this->ptsPerEdge + x][1] - this->frames[this->curFrame][(z - 1) * this->ptsPerEdge + x][1]) / 2,
|
||||
};
|
||||
|
||||
glm_vec3_normalize(n);
|
||||
|
||||
nrm[z * this->ptsPerEdge + x][0] = n[0] * 127;
|
||||
nrm[z * this->ptsPerEdge + x][1] = n[1] * 127;
|
||||
nrm[z * this->ptsPerEdge + x][2] = n[2] * 127;
|
||||
}
|
||||
}
|
||||
|
||||
k3MdlUpdateNrm(this->mdl, nrm);
|
||||
}
|
||||
|
||||
void k3WaterDisturb(struct k3Water *this, float x, float y, float radius, float powr) {
|
||||
int i = (x + this->w / 2) * this->ptsPerEdge / this->w;
|
||||
int j = (y + this->h / 2) * this->ptsPerEdge / this->h;
|
||||
|
||||
this->frames[this->curFrame][j * this->ptsPerEdge + i][1] += -powr;
|
||||
this->frames[(this->curFrame + 2) % k3_WATER_FRAMES][j * this->ptsPerEdge + i][1] += -powr;
|
||||
}
|
42
src/k3water.h
Normal file
42
src/k3water.h
Normal file
@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#include"k3.h"
|
||||
|
||||
enum k3WaterObstacleType {
|
||||
k3_WATER_OBSTACLE_CYLINDER,
|
||||
k3_WATER_OBSTACLE_RECTCUBOID
|
||||
};
|
||||
|
||||
struct k3WaterObstacle {
|
||||
enum k3WaterObstacleType type;
|
||||
float depth;
|
||||
float x;
|
||||
float y;
|
||||
union {
|
||||
float radius;
|
||||
float width;
|
||||
};
|
||||
float height;
|
||||
};
|
||||
|
||||
struct k3Water {
|
||||
struct k3Mdl *mdl;
|
||||
|
||||
float w, h;
|
||||
|
||||
#define k3_WATER_FRAMES 3
|
||||
vec3 *frames[k3_WATER_FRAMES];
|
||||
int curFrame;
|
||||
|
||||
float dx, dy;
|
||||
|
||||
int ptsPerEdge;
|
||||
|
||||
uint8_t obstacleCount, obstacleCapacity;
|
||||
struct k3WaterObstacle *obstacles;
|
||||
};
|
||||
|
||||
struct k3Water *k3WaterCreate(float w, float h, size_t subdivisions, struct k3Mat*);
|
||||
void k3WaterSimulate(struct k3Water*, float dt, float C, float mu, int substeps); //C=speed, mu=damping
|
||||
void k3WaterUpdate(struct k3Water*);
|
||||
void k3WaterDisturb(struct k3Water*, float x, float y, float radius, float powr);
|
Loading…
Reference in New Issue
Block a user