Compare commits
9 Commits
cc37e17046
...
9bc549546f
Author | SHA1 | Date | |
---|---|---|---|
![]() |
9bc549546f | ||
![]() |
2cb80f8abe | ||
![]() |
6c13a83271 | ||
![]() |
4afe4f3fbe | ||
![]() |
5e0966beb8 | ||
![]() |
c3daf57f24 | ||
![]() |
bf60cac302 | ||
![]() |
6d5ba6037c | ||
![]() |
295c882100 |
@ -4,24 +4,61 @@
|
||||
#include"k3font.h"
|
||||
#include"k3menu.h"
|
||||
|
||||
extern uint16_t GameWndH;
|
||||
|
||||
static inline void immdraw_fill_rect(int16_t x, int16_t y, int16_t w, int16_t h, float r, float g, float b, float a, float borderRadius) {
|
||||
k3BatchAdd(NULL, (struct k3RectF) {0, 0, 1, 1}, (struct k3RectF) {
|
||||
x, y,
|
||||
x, GameWndH - y - h,
|
||||
w, h
|
||||
}, 0, (vec4) {r, g, b, a}, borderRadius);
|
||||
}
|
||||
|
||||
static inline void immdraw_font_draw(struct k3Font *font, int16_t x, int16_t y, int16_t w, float sz, size_t len, const char *txt, int alignment, float r, float g, float b, float a) {
|
||||
if(alignment != k3M_ALIGN_LEFT) {
|
||||
k3FontDraw(font, x, GameWndH - y - sz, sz, txt, w, alignment, (vec4) {r, g, b, a});
|
||||
}
|
||||
static inline void immdraw_font_size(struct k3Font *font, float sz, const char *txt, int16_t wall, int16_t aabb[2]) {
|
||||
struct k3RectF txtsz;
|
||||
k3FontSz(font, sz, txt, &txtsz);
|
||||
k3FontSz(font, sz, txt, wall, &txtsz);
|
||||
|
||||
if(alignment == k3M_ALIGN_CENTER) {
|
||||
x += w / 2.0f - txtsz.w / 2.0f;
|
||||
aabb[0] = ceilf(txtsz.w);
|
||||
aabb[1] = ceilf(txtsz.h);
|
||||
}
|
||||
|
||||
static inline void immdraw_image_draw(k3MImageData *data, int16_t x, int16_t y, int16_t w, int16_t h, float r, float g, float b, float a) {
|
||||
struct k3Tex *tex = *data;
|
||||
k3BatchAdd(tex, (struct k3RectF) {0, 0, 1, 1}, (struct k3RectF) {x, GameWndH - y - h, w, h}, 0, (vec4) {r, g, b, a}, 0);
|
||||
}
|
||||
|
||||
static int16_t crop_aabb[4] = {-1, -1, -1, -1};
|
||||
static inline void immdraw_crop_get(int16_t aabb[4]) {
|
||||
memcpy(aabb, crop_aabb, sizeof(crop_aabb));
|
||||
}
|
||||
static inline void immdraw_crop_set(int16_t aabb[4]) {
|
||||
memcpy(crop_aabb, aabb, sizeof(crop_aabb));
|
||||
|
||||
if(aabb[0] == -1 && aabb[1] == -1 && aabb[2] == -1 && aabb[3] == -1) {
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
} else {
|
||||
x += w - txtsz.w;
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
glScissor(aabb[0], GameWndH - aabb[3], aabb[2] - aabb[0], aabb[3] - aabb[1]);
|
||||
}
|
||||
}
|
||||
static inline void immdraw_crop_add(int16_t aabb[4]) {
|
||||
int16_t newaabb[4];
|
||||
memcpy(newaabb, crop_aabb, sizeof(newaabb));
|
||||
|
||||
if(aabb[0] > newaabb[0] || newaabb[0] == -1) {
|
||||
newaabb[0] = aabb[0];
|
||||
}
|
||||
if(aabb[1] > newaabb[1] || newaabb[1] == -1) {
|
||||
newaabb[1] = aabb[1];
|
||||
}
|
||||
if(aabb[2] < newaabb[2] || newaabb[2] == -1) {
|
||||
newaabb[2] = aabb[2];
|
||||
}
|
||||
if(aabb[3] < newaabb[3] || newaabb[3] == -1) {
|
||||
newaabb[3] = aabb[3];
|
||||
}
|
||||
|
||||
k3FontDraw(font, x, y, sz, txt, (vec4) {r, g, b, a});
|
||||
immdraw_crop_set(newaabb);
|
||||
}
|
||||
|
194
src/k3.c
194
src/k3.c
@ -34,6 +34,8 @@ static GLenum TextureCompressionRGBA;
|
||||
static GLenum TextureCompressionSRGBA;
|
||||
static TextureOfflineCompressorFunc TextureOfflineCompressor;
|
||||
|
||||
static bool MipmappingEnabled;
|
||||
|
||||
void k3StorageRef(struct k3Storage *s) {
|
||||
s->ref++;
|
||||
}
|
||||
@ -168,7 +170,7 @@ struct k3Mdl *k3MdlCreate(size_t verts, size_t indices, size_t boneCount, vec3 *
|
||||
ret->anims = NULL;
|
||||
|
||||
if(k3IsSoftSkinning && pos && boneids && boneweights) {
|
||||
ret->cpuSkinning.pos = malloc(sizeof(*ret->cpuSkinning.pos) * verts);
|
||||
ret->cpuSkinning.pos = _mm_malloc(sizeof(*ret->cpuSkinning.pos) * verts, 16);
|
||||
memcpy(ret->cpuSkinning.pos, pos, sizeof(*ret->cpuSkinning.pos) * verts);
|
||||
|
||||
ret->cpuSkinning.boneids = malloc(sizeof(*ret->cpuSkinning.boneids) * verts * 4);
|
||||
@ -294,12 +296,12 @@ struct k3Mesh *k3MdlGetMeshes(struct k3Mdl *mdl, size_t *count) {
|
||||
return mdl->meshes;
|
||||
}
|
||||
|
||||
void k3MdlAddAnim(struct k3Mdl *mdl, struct k3Animation *anim) {
|
||||
void k3MdlAddAnim(struct k3Mdl *mdl, struct k3AnimationFountain *anim) {
|
||||
mdl->anims = realloc(mdl->anims, sizeof(*mdl->anims) * (mdl->animCount + 1));
|
||||
mdl->anims[mdl->animCount++] = anim;
|
||||
}
|
||||
|
||||
struct k3Animation *k3MdlGetAnim(struct k3Mdl *mdl, uint16_t id) {
|
||||
struct k3AnimationFountain *k3MdlGetAnim(struct k3Mdl *mdl, uint16_t id) {
|
||||
for(size_t i = 0; i < mdl->animCount; i++) {
|
||||
if(mdl->anims[i]->id == id) {
|
||||
return mdl->anims[i];
|
||||
@ -311,6 +313,16 @@ size_t k3MdlGetBoneCount(struct k3Mdl *mdl) {
|
||||
return mdl->boneCount;
|
||||
}
|
||||
|
||||
static size_t bonenames_len(size_t boneCount, const char *names) {
|
||||
const char *bn = names;
|
||||
size_t sz = 0;
|
||||
for(int b = 0; b < boneCount; b++) {
|
||||
sz += strlen(bn) + 1;
|
||||
bn += strlen(bn) + 1;
|
||||
}
|
||||
return sz;
|
||||
}
|
||||
|
||||
struct k3Mdl *k3MdlCopySubs(struct k3Mdl *src) {
|
||||
struct k3Mdl *dst = calloc(1, sizeof(*dst));
|
||||
|
||||
@ -330,10 +342,15 @@ struct k3Mdl *k3MdlCopySubs(struct k3Mdl *src) {
|
||||
memcpy(dst->meshes, src->meshes, sizeof(*dst->meshes) * dst->meshCount);
|
||||
|
||||
dst->boneCount = src->boneCount;
|
||||
dst->invBind = malloc(sizeof(*dst->invBind) * dst->boneCount);
|
||||
memcpy(dst->invBind, src->invBind, sizeof(dst->invBind) * dst->boneCount);
|
||||
dst->invBind = _mm_malloc(sizeof(*dst->invBind) * dst->boneCount, 16);
|
||||
memcpy(dst->invBind, src->invBind, sizeof(*dst->invBind) * dst->boneCount);
|
||||
dst->boneParents = malloc(sizeof(*dst->boneParents) * dst->boneCount);
|
||||
memcpy(dst->boneParents, src->boneParents, sizeof(*dst->boneParents) * dst->boneCount);
|
||||
if(src->boneNames) {
|
||||
size_t sz = bonenames_len(src->boneCount, src->boneNames);
|
||||
dst->boneNames = calloc(1, sz);
|
||||
memcpy(dst->boneNames, src->boneNames, sz);
|
||||
}
|
||||
|
||||
dst->animCount = src->animCount;
|
||||
dst->anims = malloc(sizeof(*dst->anims) * dst->animCount);
|
||||
@ -360,65 +377,113 @@ void k3MdlSetDebugName(struct k3Mdl *mdl, const char *name) {
|
||||
k3Log(k3_DEBUG, "Model name: %s", name);
|
||||
}
|
||||
|
||||
static void anim_update(struct k3Animator *anim) {
|
||||
float frame = anim->time * anim->base->fps;
|
||||
static void qwfun(struct k3Mdl *mdl, size_t b, float *output) {
|
||||
for(size_t c = b + 1; c < mdl->boneCount; c++) {
|
||||
if(mdl->boneParents[c] == b) {
|
||||
output[c] = 1;
|
||||
qwfun(mdl, c, output);
|
||||
}
|
||||
}
|
||||
}
|
||||
void k3MdlQueryWeights(struct k3Mdl *mdl, size_t boneIdx, float *output) {
|
||||
memset(output, 0, sizeof(*output) * mdl->boneCount);
|
||||
|
||||
size_t f0 = floorf(frame);
|
||||
size_t f1 = (f0 + 1);
|
||||
|
||||
float alpha = frame - f0;
|
||||
|
||||
f0 %= anim->base->frameCount;
|
||||
f1 %= anim->base->frameCount;
|
||||
|
||||
for(size_t b = 0; b < anim->base->boneCount; b++) {
|
||||
vec4 t0, t1;
|
||||
glm_vec4_copy(anim->base->frames[anim->base->boneCount * f0 + b].translation, t0);
|
||||
glm_vec4_copy(anim->base->frames[anim->base->boneCount * f1 + b].translation, t1);
|
||||
|
||||
versor r0, r1;
|
||||
glm_quat_copy(anim->base->frames[anim->base->boneCount * f0 + b].rotation, r0);
|
||||
glm_quat_copy(anim->base->frames[anim->base->boneCount * f1 + b].rotation, r1);
|
||||
|
||||
vec4 t;
|
||||
glm_vec4_lerp(t0, t1, alpha, t);
|
||||
|
||||
versor r;
|
||||
glm_quat_slerp(r0, r1, alpha, r);
|
||||
|
||||
mat4 m = GLM_MAT4_IDENTITY_INIT;
|
||||
glm_quat_mat4(r, m);
|
||||
glm_vec4_copy(t, m[3]);
|
||||
|
||||
uint8_t parent = anim->base->boneParents[b];
|
||||
if(parent != 0xFF) {
|
||||
glm_mat4_mul(anim->inter[parent], m, anim->inter[b]);
|
||||
} else {
|
||||
glm_mat4_copy(m, anim->inter[b]);
|
||||
if(boneIdx < mdl->boneCount) {
|
||||
qwfun(mdl, boneIdx, output);
|
||||
}
|
||||
}
|
||||
|
||||
for(size_t b = 0; b < anim->base->boneCount; b++) {
|
||||
glm_mat4_mul(anim->inter[b], anim->base->invBind[b], anim->inter[b]);
|
||||
intmax_t k3MdlGetBoneFromName(struct k3Mdl *mdl, const char *targetName) {
|
||||
if(!mdl->boneNames) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char *name = mdl->boneNames;
|
||||
|
||||
for(size_t b = 0; b < mdl->boneCount; b++) {
|
||||
if(!strcmp(name, targetName)) {
|
||||
return b;
|
||||
}
|
||||
|
||||
name = name + strlen(name) + 1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void k3MdlSetBoneNames(struct k3Mdl *mdl, const char *names) {
|
||||
size_t sz = bonenames_len(mdl->boneCount, names);
|
||||
mdl->boneNames = malloc(sz);
|
||||
memcpy(mdl->boneNames, names, sz);
|
||||
}
|
||||
|
||||
void k3AnimatorInit(struct k3Animator *this, struct k3Mdl *mdl) {
|
||||
this->mdl = mdl;
|
||||
|
||||
size_t boneCount = k3MdlGetBoneCount(this->mdl);
|
||||
this->bones = _mm_malloc(boneCount * sizeof(*this->bones), 16);
|
||||
for(size_t b = 0; b < boneCount; b++) {
|
||||
this->bones[b].translation[0] = 0;
|
||||
this->bones[b].translation[1] = 0;
|
||||
this->bones[b].translation[2] = 0;
|
||||
this->bones[b].translation[3] = 1;
|
||||
|
||||
this->bones[b].rotation[0] = 0;
|
||||
this->bones[b].rotation[1] = 0;
|
||||
this->bones[b].rotation[2] = 0;
|
||||
this->bones[b].rotation[3] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void k3AnimatorSet(struct k3Animator *anim, float time) {
|
||||
if(!anim->inter) anim->inter = _mm_malloc(sizeof(mat4) * anim->base->boneCount * anim->base->frameCount, 16);
|
||||
anim->time = time;
|
||||
k3AnimationUpdate(anim->anim, anim->time);
|
||||
|
||||
if(!anim->loop) {
|
||||
time = fmaxf(time, 0);
|
||||
time = fminf(time, (float) (anim->base->frameCount - 1) / anim->base->fps);
|
||||
if(!anim->bones) {
|
||||
anim->bones = _mm_malloc(sizeof(*anim->bones) * anim->anim->bones, 16);
|
||||
memset(anim->bones, 0, sizeof(*anim->bones) * anim->anim->bones);
|
||||
}
|
||||
|
||||
anim->time = time;
|
||||
if(!anim->anim->cache) {
|
||||
return;
|
||||
}
|
||||
|
||||
anim_update(anim);
|
||||
mat4 *mats = alloca(sizeof(*mats) * anim->anim->bones);
|
||||
memset(mats, 0, sizeof(*mats) * anim->anim->bones);
|
||||
|
||||
for(size_t b = 0; b < anim->anim->bones; b++) {
|
||||
mat4 m = GLM_MAT4_IDENTITY_INIT;
|
||||
glm_quat_mat4(anim->anim->cache[b].rotation, m);
|
||||
glm_vec4_copy(anim->anim->cache[b].translation, m[3]);
|
||||
|
||||
uint8_t parent = anim->mdl->boneParents[b];
|
||||
if(parent != 0xFF) {
|
||||
glm_mat4_mul(mats[parent], m, mats[b]);
|
||||
} else {
|
||||
glm_mat4_copy(m, mats[b]);
|
||||
}
|
||||
}
|
||||
for(size_t b = 0; b < anim->anim->bones; b++) {
|
||||
glm_mat4_mul(mats[b], anim->mdl->invBind[b], mats[b]);
|
||||
}
|
||||
for(size_t b = 0; b < anim->anim->bones; b++) {
|
||||
vec4 t;
|
||||
mat4 r;
|
||||
vec3 s;
|
||||
glm_decompose(mats[b], t, r, s);
|
||||
|
||||
t[3] = 1;
|
||||
glm_vec4_copy(t, anim->bones[b].translation);
|
||||
|
||||
versor q;
|
||||
glm_mat4_quat(r, q);
|
||||
glm_quat_copy(q, anim->bones[b].rotation);
|
||||
}
|
||||
}
|
||||
void k3AnimatorStep(struct k3Animator *anim, float dt) {
|
||||
k3AnimatorSet(anim, anim->time + dt);
|
||||
}
|
||||
|
||||
|
||||
struct k3Tex *k3TexCreate(enum k3TexType type) {
|
||||
struct k3Tex *ret = calloc(1, sizeof(*ret));
|
||||
|
||||
@ -508,6 +573,10 @@ void k3TexUpdate(struct k3Tex *tex, enum k3TexType type, int index, uint16_t wid
|
||||
break;
|
||||
}
|
||||
|
||||
if(!MipmappingEnabled) {
|
||||
mipmap = 0;
|
||||
}
|
||||
|
||||
if(!tex->tex) {
|
||||
glGenTextures(1, &tex->tex);
|
||||
glBindTexture(target, tex->tex);
|
||||
@ -1464,7 +1533,7 @@ static void forward_subpass(mat4 projection, mat4 view, int transparent, int lig
|
||||
}
|
||||
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat->primitive.specular);
|
||||
glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, mat->primitive.emission);
|
||||
glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, mat->primitive.shininess * 128);
|
||||
glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, mat->primitive.shininess);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1499,7 +1568,7 @@ static void forward_subpass(mat4 projection, mat4 view, int transparent, int lig
|
||||
enable_glsl_tangents(glsl, mdl);
|
||||
}
|
||||
|
||||
if(k3IsSoftSkinning) {
|
||||
if(k3IsSoftSkinning && bones) {
|
||||
apply_cpu_skinning(mdl, bones);
|
||||
}
|
||||
|
||||
@ -1694,7 +1763,7 @@ void k3PassDepthOnly(mat4 projection, mat4 cam, int clear, int cull) {
|
||||
enable_glsl_bones(glsl, mdl, bones);
|
||||
}
|
||||
|
||||
if(k3IsSoftSkinning) {
|
||||
if(k3IsSoftSkinning && bones) {
|
||||
apply_cpu_skinning(mdl, bones);
|
||||
}
|
||||
|
||||
@ -1940,7 +2009,7 @@ static void pass_irregular(int passnum, mat4 mainproj, mat4 maincam, mat4 lightp
|
||||
enable_glsl_bones(glsl, mdl, bones);
|
||||
}
|
||||
|
||||
if(k3IsSoftSkinning) {
|
||||
if(k3IsSoftSkinning && bones) {
|
||||
apply_cpu_skinning(mdl, bones);
|
||||
}
|
||||
|
||||
@ -2366,7 +2435,7 @@ static void *compress_rgba_bc7(const void *pixels, uint16_t width, uint16_t heig
|
||||
return output;
|
||||
}
|
||||
|
||||
void k3Init() {
|
||||
void k3Init(bool enableTextureCompression, bool enableMipmapping) {
|
||||
if(GLAD_GL_ARB_debug_output) {
|
||||
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
|
||||
glDebugMessageCallbackARB(GlCallback, NULL);
|
||||
@ -2420,11 +2489,12 @@ void k3Init() {
|
||||
"in vec3 v_uv;\n"
|
||||
"out vec4 fragcolor;\n"
|
||||
"void main() {\n"
|
||||
" fragcolor = textureCube(u_tex, v_uv);\n"
|
||||
" fragcolor = texture(u_tex, v_uv);\n"
|
||||
"}\n"
|
||||
, NULL), NULL);
|
||||
}
|
||||
|
||||
if(enableTextureCompression) {
|
||||
/*if(GLAD_GL_KHR_texture_compression_astc_ldr) {
|
||||
TextureCompressionEnabled = true;
|
||||
|
||||
@ -2441,6 +2511,11 @@ void k3Init() {
|
||||
TextureCompressionSRGBA = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT;
|
||||
TextureCompressionRGBA = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
|
||||
}
|
||||
} else {
|
||||
TextureCompressionEnabled = false;
|
||||
}
|
||||
|
||||
MipmappingEnabled = enableMipmapping;
|
||||
}
|
||||
|
||||
static size_t preprocess(char *src, const char*(*ldr)(const char *fn), const char ***strs, GLuint **sizes) {
|
||||
@ -2651,6 +2726,7 @@ struct k3GLSLP *k3ProgramGLSL(struct k3GLSLV *vs, struct k3GLSLF *fs, struct k3G
|
||||
GLint uniformCount;
|
||||
glGetObjectParameterivARB(prog, GL_OBJECT_ACTIVE_UNIFORMS_ARB, &uniformCount);
|
||||
|
||||
|
||||
for(i = 0; i < uniformCount; i++) {
|
||||
int size;
|
||||
int type;
|
||||
@ -2923,15 +2999,19 @@ void k3BlitToScreenEffect(struct k3Offscreen *offscr, int additive, int effect,
|
||||
}
|
||||
|
||||
if(k3IsCore) {
|
||||
GLuint prog;
|
||||
|
||||
if(effect == k3_NONE) {
|
||||
glUseProgram(GL_FROM_K3GLSL(basicBlitProgram));
|
||||
prog = GL_FROM_K3GLSL(basicBlitProgram);
|
||||
} else {
|
||||
assert(effect == k3_GLSL);
|
||||
|
||||
glUseProgram(GL_FROM_K3GLSL(program));
|
||||
prog = GL_FROM_K3GLSL(program);
|
||||
}
|
||||
|
||||
GLint uSz = glGetUniformLocation(GL_FROM_K3GLSL(basicBlitProgram), "u_sz");
|
||||
glUseProgram(prog);
|
||||
|
||||
GLint uSz = glGetUniformLocation(prog, "u_sz");
|
||||
glUniform2f(uSz, k3TexSzX(tex), k3TexSzY(tex));
|
||||
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
|
41
src/k3.h
41
src/k3.h
@ -5,12 +5,13 @@
|
||||
#include<cglm/vec3.h>
|
||||
#include<cglm/mat4.h>
|
||||
#include<cglm/quat.h>
|
||||
#include"k3anim.h"
|
||||
|
||||
#ifdef k3_MULTITHREAD
|
||||
#include<pthread.h>
|
||||
#endif
|
||||
|
||||
void k3Init();
|
||||
void k3Init(bool tc, bool mipmap);
|
||||
void k3Resize(uint16_t width, uint16_t height);
|
||||
void k3Update();
|
||||
|
||||
@ -101,27 +102,17 @@ struct k3Mat {
|
||||
} 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;
|
||||
struct k3Mdl *mdl;
|
||||
|
||||
mat4 *inter;
|
||||
struct k3AnimationBone *bones;
|
||||
|
||||
struct k3Animation *base;
|
||||
struct k3Animation *anim;
|
||||
|
||||
double time;
|
||||
|
||||
bool playing;
|
||||
double playStartTime;
|
||||
};
|
||||
|
||||
struct k3Offscreen;
|
||||
@ -170,14 +161,16 @@ struct k3Mdl *k3MdlCreate(size_t verts, size_t indices, size_t boneCount, vec3 *
|
||||
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);
|
||||
void k3MdlAddAnim(struct k3Mdl*, struct k3AnimationFountain*);
|
||||
struct k3AnimationFountain *k3MdlGetAnim(struct k3Mdl*, uint16_t id);
|
||||
size_t k3MdlGetBoneCount(struct k3Mdl*);
|
||||
|
||||
void k3MdlSetDebugName(struct k3Mdl*, const char*);
|
||||
|
||||
struct k3Mdl *k3MdlCopySubs(struct k3Mdl*);
|
||||
void k3MdlSetDebugName(struct k3Mdl*, const char*);
|
||||
void k3MdlQueryWeights(struct k3Mdl*, size_t bone, float *output);
|
||||
intmax_t k3MdlGetBoneFromName(struct k3Mdl*, const char*);
|
||||
void k3MdlSetBoneNames(struct k3Mdl*, const char*);
|
||||
|
||||
void k3AnimatorInit(struct k3Animator*, struct k3Mdl*);
|
||||
void k3AnimatorSet(struct k3Animator*, float);
|
||||
void k3AnimatorStep(struct k3Animator*, float);
|
||||
|
||||
|
@ -14,6 +14,8 @@
|
||||
#define GL_FROM_K3ARBFP(k3m) ((GLuint) (uintptr_t) (k3m))
|
||||
#define GL_FROM_K3GLSL(k3m) ((GLuint) (uintptr_t) (k3m))
|
||||
|
||||
extern bool k3IsCore;
|
||||
|
||||
struct k3Tex {
|
||||
GLuint tex;
|
||||
int cubemap;
|
||||
@ -71,9 +73,10 @@ struct k3Mdl {
|
||||
size_t boneCount;
|
||||
mat4 *invBind;
|
||||
uint8_t *boneParents;
|
||||
char *boneNames;
|
||||
|
||||
uint16_t animCount;
|
||||
struct k3Animation **anims;
|
||||
struct k3AnimationFountain **anims;
|
||||
|
||||
vec3 aabb[2];
|
||||
|
||||
|
185
src/k3anim.c
Normal file
185
src/k3anim.c
Normal file
@ -0,0 +1,185 @@
|
||||
#include"k3anim.h"
|
||||
|
||||
#include<cglm/mat4.h>
|
||||
#include<cglm/quat.h>
|
||||
#include<stdint.h>
|
||||
#include<stddef.h>
|
||||
|
||||
static uint32_t lcg() {
|
||||
static uint32_t asdf = 0;
|
||||
asdf = asdf * 1664525 + 1013904223;
|
||||
return asdf;
|
||||
}
|
||||
|
||||
static void power_iter(mat4 M, int iterations, float eps, vec4 ev) {
|
||||
// Random starting vector
|
||||
uint32_t rng = lcg();
|
||||
ev[0] = (rng & 0xFF) / 255.f;
|
||||
rng >>= 8;
|
||||
ev[1] = (rng & 0xFF) / 255.f;
|
||||
rng >>= 8;
|
||||
ev[2] = (rng & 0xFF) / 255.f;
|
||||
rng >>= 8;
|
||||
ev[3] = rng / 255.f;
|
||||
|
||||
for(int i = 0; i < iterations; i++) {
|
||||
vec4 k;
|
||||
glm_mat4_mulv(M, ev, k);
|
||||
glm_vec4_normalize_to(k, ev);
|
||||
}
|
||||
}
|
||||
|
||||
static void quat_to_mat(versor v, mat4 m) {
|
||||
for(int y = 0; y < 4; y++) {
|
||||
for(int x = 0; x < 4; x++) {
|
||||
m[y][x] = v[y] * v[x];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool k3AnimationUpdate(struct k3Animation *anim, float time) {
|
||||
if(anim->op == k3_ANIM_BASIC) {
|
||||
struct k3AnimationBasic *basic = (void*) anim;
|
||||
struct k3AnimationFountain *fountain = basic->fountain;
|
||||
|
||||
if(!anim->cache) {
|
||||
anim->bones = fountain->bones;
|
||||
anim->cache = _mm_malloc(sizeof(*anim->cache) * anim->bones, 16);
|
||||
}
|
||||
|
||||
float frame = time * fountain->fps;
|
||||
|
||||
if(!basic->loop) {
|
||||
frame = fminf(frame, fountain->frameCount - 1);
|
||||
}
|
||||
|
||||
size_t f0 = floorf(frame);
|
||||
size_t f1 = (f0 + 1);
|
||||
|
||||
float alpha = frame - f0;
|
||||
|
||||
f0 %= fountain->frameCount;
|
||||
f1 %= fountain->frameCount;
|
||||
|
||||
for(size_t b = 0; b < fountain->bones; b++) {
|
||||
vec4 t0, t1;
|
||||
glm_vec4_copy(fountain->frames[fountain->bones * f0 + b].translation, t0);
|
||||
glm_vec4_copy(fountain->frames[fountain->bones * f1 + b].translation, t1);
|
||||
|
||||
versor r0, r1;
|
||||
glm_quat_copy(fountain->frames[fountain->bones * f0 + b].rotation, r0);
|
||||
glm_quat_copy(fountain->frames[fountain->bones * f1 + b].rotation, r1);
|
||||
|
||||
glm_vec4_lerp(t0, t1, alpha, basic->cache[b].translation);
|
||||
glm_quat_slerp(r0, r1, alpha, basic->cache[b].rotation);
|
||||
}
|
||||
|
||||
return true;
|
||||
} else if(anim->op == k3_ANIM_BLEND) {
|
||||
struct k3AnimationBlend *blend = (void*) anim;
|
||||
|
||||
if(blend->children == 0) return false;
|
||||
|
||||
if(!blend->cache || blend->bones != blend->subs[0]->bones) {
|
||||
if(blend->cache) _mm_free(blend->cache);
|
||||
|
||||
blend->bones = blend->subs[0]->bones;
|
||||
blend->cache = _mm_malloc(blend->bones * sizeof(*blend->cache), 16);
|
||||
}
|
||||
|
||||
for(size_t c = 0; c < blend->children; c++) {
|
||||
if(!k3AnimationUpdate(blend->subs[c], blend->offsets[c] + time * blend->speeds[c])) return false;
|
||||
if(blend->subs[c]->bones != blend->bones) return false;
|
||||
}
|
||||
|
||||
for(size_t b = 0; b < blend->bones; b++) {
|
||||
float weightSum = 0;
|
||||
vec4 translationSum = GLM_VEC4_ZERO_INIT;
|
||||
mat4 rotationSum = GLM_MAT4_ZERO_INIT;
|
||||
|
||||
for(size_t c = 0; c < blend->children; c++) {
|
||||
float w = blend->weights[c * blend->bones + b];
|
||||
|
||||
weightSum += w;
|
||||
|
||||
glm_vec4_muladds(blend->subs[c]->cache[b].translation, w, translationSum);
|
||||
|
||||
mat4 rm;
|
||||
quat_to_mat(blend->subs[c]->cache[b].rotation, rm);
|
||||
glm_mat4_scale(rm, w);
|
||||
|
||||
glm_vec4_add(rotationSum[0], rm[0], rotationSum[0]);
|
||||
glm_vec4_add(rotationSum[1], rm[1], rotationSum[1]);
|
||||
glm_vec4_add(rotationSum[2], rm[2], rotationSum[2]);
|
||||
glm_vec4_add(rotationSum[3], rm[3], rotationSum[3]);
|
||||
}
|
||||
|
||||
glm_vec4_scale(translationSum, 1.0f / weightSum, blend->cache[b].translation);
|
||||
|
||||
vec4 dominantEigenVector;
|
||||
power_iter(rotationSum, 64, 1e-5f, dominantEigenVector);
|
||||
glm_vec4_normalize(dominantEigenVector);
|
||||
glm_quat_copy((float*) dominantEigenVector, blend->cache[b].rotation);
|
||||
}
|
||||
|
||||
return true;
|
||||
} else if(anim->op == k3_ANIM_ADD) {
|
||||
struct k3AnimationAdd *add = (void*) anim;
|
||||
|
||||
if(!k3AnimationUpdate(add->sub1, time)) return false;
|
||||
if(!k3AnimationUpdate(add->sub2, time)) return false;
|
||||
|
||||
if(!add->cache || add->bones != add->sub1->bones) {
|
||||
if(add->cache) _mm_free(add->cache);
|
||||
|
||||
add->bones = add->sub1->bones;
|
||||
add->cache = _mm_malloc(add->bones * sizeof(*add->cache), 16);
|
||||
}
|
||||
|
||||
versor norot = {0, 0, 0, 1};
|
||||
|
||||
for(size_t b = 0; b < add->bones; b++) {
|
||||
glm_vec4_copy(add->sub1->cache[b].translation, add->cache[b].translation);
|
||||
glm_vec4_muladds(add->sub2->cache[b].translation, add->scale, add->cache[b].translation);
|
||||
|
||||
versor o;
|
||||
glm_quat_nlerp(norot, add->sub2->cache[b].rotation, add->scale, o);
|
||||
glm_quat_mul(o, add->sub1->cache[b].rotation, add->cache[b].rotation);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void k3AnimationFree(struct k3Animation *anim) {
|
||||
if(!anim) return;
|
||||
|
||||
if(anim->ref != 0) {
|
||||
anim->ref--;
|
||||
return;
|
||||
}
|
||||
|
||||
if(anim->op == k3_ANIM_BLEND) {
|
||||
struct k3AnimationBlend *blend = (void*) anim;
|
||||
|
||||
for(size_t c = 0; c < blend->children; c++) {
|
||||
k3AnimationFree(blend->subs[c]);
|
||||
}
|
||||
free(blend->subs);
|
||||
|
||||
free(blend->weights);
|
||||
free(blend->offsets);
|
||||
free(blend->speeds);
|
||||
} else if(anim->op == k3_ANIM_ADD) {
|
||||
struct k3AnimationAdd *add = (void*) anim;
|
||||
|
||||
k3AnimationFree(add->sub1);
|
||||
k3AnimationFree(add->sub2);
|
||||
}
|
||||
|
||||
_mm_free(anim->cache);
|
||||
|
||||
free(anim);
|
||||
}
|
70
src/k3anim.h
Normal file
70
src/k3anim.h
Normal file
@ -0,0 +1,70 @@
|
||||
#pragma once
|
||||
|
||||
#include<cglm/mat4.h>
|
||||
#include<cglm/quat.h>
|
||||
#include<stdint.h>
|
||||
#include<stddef.h>
|
||||
|
||||
struct k3AnimationBone {
|
||||
vec4 translation;
|
||||
versor rotation;
|
||||
};
|
||||
|
||||
enum k3AnimationOp {
|
||||
k3_ANIM_BASIC,
|
||||
k3_ANIM_BLEND,
|
||||
k3_ANIM_ADD,
|
||||
};
|
||||
|
||||
struct k3AnimationFountain {
|
||||
float fps;
|
||||
size_t frameCount;
|
||||
size_t bones;
|
||||
uint16_t id;
|
||||
_Alignas(16) struct k3AnimationBone frames[];
|
||||
};
|
||||
|
||||
struct k3Animation {
|
||||
enum k3AnimationOp op;
|
||||
size_t bones;
|
||||
struct k3AnimationBone *cache;
|
||||
size_t ref;
|
||||
};
|
||||
|
||||
struct k3AnimationBasic {
|
||||
enum k3AnimationOp op;
|
||||
size_t bones;
|
||||
struct k3AnimationBone *cache;
|
||||
size_t ref;
|
||||
|
||||
struct k3AnimationFountain *fountain;
|
||||
bool loop;
|
||||
};
|
||||
|
||||
struct k3AnimationBlend {
|
||||
enum k3AnimationOp op;
|
||||
size_t bones;
|
||||
struct k3AnimationBone *cache;
|
||||
size_t ref;
|
||||
|
||||
size_t children;
|
||||
float *offsets;
|
||||
float *speeds;
|
||||
float *weights;
|
||||
struct k3Animation **subs;
|
||||
};
|
||||
|
||||
struct k3AnimationAdd {
|
||||
enum k3AnimationOp op;
|
||||
size_t bones;
|
||||
struct k3AnimationBone *cache;
|
||||
size_t ref;
|
||||
|
||||
struct k3Animation *sub1;
|
||||
struct k3Animation *sub2;
|
||||
|
||||
float scale;
|
||||
};
|
||||
|
||||
bool k3AnimationUpdate(struct k3Animation *anim, float time);
|
||||
void k3AnimationFree(struct k3Animation *anim);
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include"gl.h"
|
||||
#include<string.h>
|
||||
#include"k3_internal.h"
|
||||
|
||||
struct S {
|
||||
struct k3RectF src;
|
||||
@ -19,6 +20,10 @@ static struct S *S;
|
||||
|
||||
static struct k3GLSLP *coreProg;
|
||||
static GLuint coreVBO;
|
||||
static GLuint coreUResolution;
|
||||
|
||||
static float ResolutionX;
|
||||
static float ResolutionY;
|
||||
|
||||
void k3BatchInit() {
|
||||
if(k3IsCore) {
|
||||
@ -31,11 +36,12 @@ void k3BatchInit() {
|
||||
"out vec2 v_uv;\n"
|
||||
"out vec4 v_color;\n"
|
||||
"out vec2 v_size;\n"
|
||||
"uniform vec2 u_resolution;\n"
|
||||
"void main() {\n"
|
||||
" v_uv = a_uv;\n"
|
||||
" v_color = a_color;\n"
|
||||
" v_size = a_size;\n"
|
||||
" gl_Position = vec4(vec2(a_pos.x / 3600.0, a_pos.y / 2025.0) * 2.0 - 1.0, 0.0, 1.0);\n"
|
||||
" gl_Position = vec4(vec2(a_pos.x / u_resolution.x, a_pos.y / u_resolution.y) * 2.0 - 1.0, 0.0, 1.0);\n"
|
||||
"}\n"
|
||||
, NULL), k3ShaderGLSLF(
|
||||
"#version 330\n"
|
||||
@ -58,6 +64,8 @@ void k3BatchInit() {
|
||||
"}\n"
|
||||
, NULL), NULL);
|
||||
|
||||
coreUResolution = k3ProgramGetUId(coreProg, "u_resolution");
|
||||
|
||||
glGenBuffers(1, &coreVBO);
|
||||
}
|
||||
}
|
||||
@ -101,6 +109,7 @@ void k3BatchFlush() {
|
||||
}
|
||||
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_CULL_FACE);
|
||||
|
||||
if(GLAD_GL_ARB_vertex_program) {
|
||||
glDisable(GL_VERTEX_PROGRAM_ARB);
|
||||
@ -124,6 +133,7 @@ void k3BatchFlush() {
|
||||
|
||||
if(k3IsCore) {
|
||||
glUseProgram((GLuint) coreProg);
|
||||
glUniform2f(coreUResolution, ResolutionX, ResolutionY);
|
||||
|
||||
float *farr = alloca(SCount * 60 * sizeof(*farr));
|
||||
|
||||
@ -257,3 +267,16 @@ void k3BatchFlush() {
|
||||
|
||||
SCount = 0;
|
||||
}
|
||||
|
||||
void k3BatchSetResolution(float w, float h) {
|
||||
ResolutionX = w;
|
||||
ResolutionY = h;
|
||||
|
||||
if(!k3IsCore) {
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glOrtho(0, ResolutionX, 0, ResolutionY, -1, 1);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
}
|
||||
}
|
||||
|
@ -12,3 +12,5 @@ struct k3RectF {
|
||||
|
||||
void k3BatchAdd(struct k3Tex *tex, struct k3RectF src, struct k3RectF dst, float rot, vec4 color, float borderRadius);
|
||||
void k3BatchFlush();
|
||||
|
||||
void k3BatchSetResolution(float w, float h);
|
||||
|
86
src/k3font.c
86
src/k3font.c
@ -97,33 +97,89 @@ static uint32_t read_utf8(const char **txt_) {
|
||||
}
|
||||
}
|
||||
|
||||
void k3FontSz(struct k3Font *this, float sz, const char *txt, struct k3RectF *ret) {
|
||||
float x = 0, y = 0;
|
||||
void k3FontSz(struct k3Font *this, float sz, const char *txt, float wall, struct k3RectF *ret) {
|
||||
if(wall < 0) {
|
||||
wall = HUGE_VALF;
|
||||
}
|
||||
|
||||
float maxX = 0;
|
||||
|
||||
float x = 0, y = sz;
|
||||
while(1) {
|
||||
uint32_t cp = read_utf8(&txt);
|
||||
|
||||
if(!cp) break;
|
||||
if(cp == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(cp == 10) {
|
||||
x = 0;
|
||||
y += sz;
|
||||
}
|
||||
|
||||
struct k3FontGlyph *g = k3FontGetGlyph(this, cp);
|
||||
|
||||
if(!g) continue;
|
||||
|
||||
if(x + g->width * this->lineScale * sz > wall) {
|
||||
x = 0;
|
||||
y += sz;
|
||||
}
|
||||
|
||||
x += g->xadvance * this->lineScale * sz;
|
||||
maxX = fmaxf(maxX, x);
|
||||
}
|
||||
ret->w = x;
|
||||
|
||||
ret->w = maxX;
|
||||
ret->h = y;
|
||||
}
|
||||
void k3FontDraw(struct k3Font *this, float xStart, float yStart, float sz, const char *txt, vec4 color) {
|
||||
float x = xStart, y = yStart;
|
||||
void k3FontDraw(struct k3Font *this, float xStart, float yStart, float sz, const char *txt, float wall, int alignment, vec4 color) {
|
||||
if(wall < 0) {
|
||||
wall = HUGE_VALF;
|
||||
}
|
||||
|
||||
float y = yStart;
|
||||
|
||||
while(1) {
|
||||
uint32_t cp = read_utf8(&txt);
|
||||
size_t lineLength = 0;
|
||||
|
||||
if(!cp) break;
|
||||
float lineWidth = 0;
|
||||
|
||||
if(cp == 10) {
|
||||
x = xStart;
|
||||
y -= sz;
|
||||
uint32_t cp2;
|
||||
const char *txt2 = txt;
|
||||
while(1) {
|
||||
cp2 = read_utf8(&txt2);
|
||||
if(cp2 == 0 || cp2 == 10) {
|
||||
break;
|
||||
}
|
||||
|
||||
lineLength++;
|
||||
|
||||
struct k3FontGlyph *g = k3FontGetGlyph(this, cp2);
|
||||
if(g) {
|
||||
if(lineWidth + g->width * this->lineScale * sz > wall) {
|
||||
break;
|
||||
}
|
||||
lineWidth += g->xadvance * this->lineScale * sz;
|
||||
}
|
||||
}
|
||||
|
||||
if(lineLength == 0 && cp2 == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
float x = 0;
|
||||
if(alignment == 0) {
|
||||
x = xStart;
|
||||
} else if(alignment == 1) {
|
||||
x = xStart + (wall - lineWidth) / 2;
|
||||
} else if(alignment == 2) {
|
||||
x = xStart + wall - lineWidth;
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < lineLength; i++) {
|
||||
uint32_t cp = read_utf8(&txt);
|
||||
|
||||
struct k3FontGlyph *g = k3FontGetGlyph(this, cp);
|
||||
|
||||
if(!g) continue;
|
||||
@ -143,6 +199,14 @@ void k3FontDraw(struct k3Font *this, float xStart, float yStart, float sz, const
|
||||
|
||||
x += g->xadvance * this->lineScale * sz;
|
||||
}
|
||||
|
||||
// If the line break was caused directly by a LF, skip over it for next line
|
||||
if(cp2 == 10) {
|
||||
read_utf8(&txt);
|
||||
}
|
||||
|
||||
y -= sz;
|
||||
}
|
||||
k3BatchFlush();
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,10 @@
|
||||
#include"k3batch.h"
|
||||
#include<string.h>
|
||||
|
||||
#define k3_FONT_ALIGN_LEFT 0
|
||||
#define k3_FONT_ALIGN_CENTER 1
|
||||
#define k3_FONT_ALIGN_RIGHT 2
|
||||
|
||||
struct k3FontGlyph {
|
||||
uint32_t cp;
|
||||
uint16_t x;
|
||||
@ -38,8 +42,8 @@ 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);
|
||||
void k3FontSz(struct k3Font*, float sz, const char *txt, float wall, struct k3RectF *ret);
|
||||
void k3FontDraw(struct k3Font*, float x, float y, float sz, const char *txt, float wall, int alignment, vec4 color);
|
||||
|
||||
struct k3FontGlyph *k3FontGetGlyph(struct k3Font*, uint32_t cp);
|
||||
|
||||
|
480
src/k3menu.c
480
src/k3menu.c
@ -1,5 +1,6 @@
|
||||
#include"k3menu.h"
|
||||
|
||||
#include"gl.h"
|
||||
#include<string.h>
|
||||
#include<stdio.h>
|
||||
#include<GLFW/glfw3.h>
|
||||
@ -36,6 +37,15 @@ void k3MArrange(struct k3MObj *this) {
|
||||
for(size_t c = 0; c < this->childCount; c++) {
|
||||
k3MArrange(this->children[c]);
|
||||
}
|
||||
|
||||
newev = (struct k3MEvent) {
|
||||
.code = k3M_EVENT_POST_ARRANGE,
|
||||
.kind = k3M_EVENTKIND_DIRECT,
|
||||
|
||||
.original = (void*) this,
|
||||
.target = (void*) this,
|
||||
};
|
||||
k3MEventSend(&newev);
|
||||
}
|
||||
|
||||
static bool linear_measure(struct k3MEvent *ev, uint8_t *ud) {
|
||||
@ -44,6 +54,7 @@ static bool linear_measure(struct k3MEvent *ev, uint8_t *ud) {
|
||||
o->wDesired = 0;
|
||||
o->hDesired = 0;
|
||||
|
||||
intmax_t prevChildMargin[4] = {};
|
||||
for(size_t i = 0; i < o->childCount; i++) {
|
||||
struct k3MObj *c = o->children[i];
|
||||
|
||||
@ -51,22 +62,51 @@ static bool linear_measure(struct k3MEvent *ev, uint8_t *ud) {
|
||||
o->wDesired = c->wDesired;
|
||||
}
|
||||
|
||||
o->hDesired += c->hDesired;
|
||||
intmax_t margin[4] = {};
|
||||
struct k3MProperty *prop = k3MFindProperty(o, k3M_PROP_MARGIN, true);
|
||||
if(prop) {
|
||||
for(int s = 0; s < 4; s++) {
|
||||
if(prop->units[s] == k3M_UNIT_ABSOLUTE) {
|
||||
margin[s] = prop->f[s];
|
||||
} else if(prop->units[s] == k3M_UNIT_PROPORTION && o->parent) {
|
||||
margin[s] = prop->f[s] * (s % 2 == 0 ? o->h : o->w);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
o->hDesired += margin[0] + c->hDesired + margin[2];
|
||||
}
|
||||
}
|
||||
static bool linear_arrange(struct k3MEvent *ev, uint8_t *ud) {
|
||||
struct k3MObj *o = ev->target;
|
||||
|
||||
size_t y = o->y;
|
||||
intmax_t padding[4] = {};
|
||||
struct k3MProperty *paddingProp = k3MFindProperty(o, k3M_PROP_PADDING, true);
|
||||
if(paddingProp) {
|
||||
for(int s = 0; s < 4; s++) {
|
||||
if(paddingProp->units[s] == k3M_UNIT_ABSOLUTE) {
|
||||
padding[s] = paddingProp->f[s];
|
||||
} else if(paddingProp->units[s] == k3M_UNIT_PROPORTION && o->parent) {
|
||||
padding[s] = paddingProp->f[s] * (s % 2 == 0 ? o->h : o->w);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t y = o->y + padding[0];
|
||||
|
||||
for(size_t i = 0; i < o->childCount; i++) {
|
||||
struct k3MObj *c = o->children[i];
|
||||
|
||||
c->x = o->x;
|
||||
c->x = o->x + padding[3];
|
||||
c->y = y;
|
||||
|
||||
c->w = c->wDesired;
|
||||
if(c->w > o->w - padding[1] - padding[3]) {
|
||||
c->w = o->w - padding[1] - padding[3];
|
||||
}
|
||||
|
||||
if(!k3MEventSend(&(struct k3MEvent) {.original = o, .target = c, .code = k3M_EVENT_SET_HEIGHT_FROM_WIDTH})) {
|
||||
c->h = c->hDesired;
|
||||
}
|
||||
|
||||
y += c->h;
|
||||
}
|
||||
@ -115,14 +155,25 @@ int k3MRegisterEventHandler_(struct k3MObj *obj, uint16_t evcode, k3MEventHandle
|
||||
}
|
||||
|
||||
bool k3MEventSend(struct k3MEvent *ev) {
|
||||
struct k3MObj *target = ev->target; // ev->target can change
|
||||
|
||||
int16_t aabb[4];
|
||||
if(ev->code == k3M_EVENT_DRAW && target->crop) {
|
||||
immdraw_crop_get(aabb);
|
||||
immdraw_crop_add(&(int16_t[4]) {target->x, target->y, target->x + target->w, target->y + target->h});
|
||||
}
|
||||
|
||||
bool status;
|
||||
while(!event_send_nonrecur(ev)) {
|
||||
if(ev->kind == k3M_EVENTKIND_DIRECT) {
|
||||
return false;
|
||||
status = false;
|
||||
goto ret;
|
||||
} else if(ev->kind == k3M_EVENTKIND_BUBBLE) {
|
||||
ev->target = ev->target->parent;
|
||||
|
||||
if(ev->target == ev->original || !ev->target) {
|
||||
return false;
|
||||
status = false;
|
||||
goto ret;
|
||||
}
|
||||
} else if(ev->kind == k3M_EVENTKIND_CAPTURE) {
|
||||
struct k3MObj *parent = ev->target;
|
||||
@ -132,23 +183,32 @@ bool k3MEventSend(struct k3MEvent *ev) {
|
||||
ev->target = parent->children[i];
|
||||
|
||||
if(k3MEventSend(ev)) {
|
||||
return true;
|
||||
status = true;
|
||||
goto ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
status = false;
|
||||
goto ret;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
status = true;
|
||||
|
||||
ret:
|
||||
if(ev->code == k3M_EVENT_DRAW && target->crop) {
|
||||
immdraw_crop_set(aabb);
|
||||
}
|
||||
|
||||
static void obj_draw(struct k3MObj *this) {
|
||||
struct k3MProperty *borderRadiusProp = k3MFindProperty(this, k3M_PROP_BORDER_RADIUS, false);
|
||||
return status;
|
||||
}
|
||||
|
||||
static void obj_draw_direct(struct k3MObj *this) {
|
||||
struct k3MProperty *borderRadiusProp = k3MFindProperty(this, k3M_PROP_BORDER_RADIUS, true);
|
||||
float borderRadius = borderRadiusProp ? borderRadiusProp->si[0] : 0;
|
||||
|
||||
struct k3MProperty *bgColorProp = k3MFindProperty(this, k3M_PROP_BG_COLOR, false);
|
||||
struct k3MProperty *bgColorProp = k3MFindProperty(this, k3M_PROP_BG_COLOR, true);
|
||||
vec4 bgColor = {0, 0, 0, 0};
|
||||
if(bgColorProp) {
|
||||
bgColor[0] = bgColorProp->si[0] / 255.0;
|
||||
@ -165,21 +225,61 @@ static void obj_draw(struct k3MObj *this) {
|
||||
static bool label_draw(struct k3MEvent *ev, uint8_t *ud) {
|
||||
struct k3MLabel *this = (void*) ev->target;
|
||||
|
||||
obj_draw((void*) this);
|
||||
obj_draw_direct((void*) this);
|
||||
|
||||
if(this->txt) {
|
||||
int alignment = k3M_ALIGN_CENTER;
|
||||
float sz = this->sz;
|
||||
struct k3MProperty *prop = k3MFindProperty(this, k3M_PROP_FONT_SIZE, false);
|
||||
if(prop) sz = prop->f[0];
|
||||
|
||||
struct k3MProperty *prop = k3MFindProperty(this, k3M_PROP_HORIZONTAL_ALIGNMENT, false);
|
||||
if(prop) alignment = prop->si[0];
|
||||
int ha = k3M_ALIGN_LEFT;
|
||||
prop = k3MFindProperty(this, k3M_PROP_HORIZONTAL_ALIGNMENT, false);
|
||||
if(prop) ha = prop->si[0];
|
||||
|
||||
immdraw_font_draw(this->font, this->x, this->y, this->w, this->sz, strlen(this->txt), this->txt, alignment,
|
||||
int va = k3M_ALIGN_CENTER;
|
||||
prop = k3MFindProperty(this, k3M_PROP_VERTICAL_ALIGNMENT, false);
|
||||
if(prop) va = prop->si[0];
|
||||
|
||||
int16_t x = this->x;
|
||||
int16_t y = this->y;
|
||||
|
||||
if(va != k3M_ALIGN_TOP) {
|
||||
struct k3RectF txtsz;
|
||||
k3FontSz(this->font, this->sz, this->txt, this->w, &txtsz);
|
||||
if(va == k3M_ALIGN_CENTER) {
|
||||
y += (this->h - txtsz.h) / 2;
|
||||
} else if(va == k3M_ALIGN_BOTTOM) {
|
||||
y += this->h - txtsz.h;
|
||||
}
|
||||
}
|
||||
|
||||
immdraw_font_draw(this->font, x, y, this->w, sz, strlen(this->txt), this->txt, ha,
|
||||
1, 1, 1, 1);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
static bool label_measure(struct k3MEvent *ev, uint8_t *ud) {
|
||||
struct k3MLabel *this = (void*) ev->target;
|
||||
|
||||
struct k3RectF txtsz;
|
||||
k3FontSz(this->font, this->sz, this->txt, -1, &txtsz);
|
||||
|
||||
this->w = ceilf(txtsz.w);
|
||||
this->h = ceilf(txtsz.h);
|
||||
|
||||
return false;
|
||||
}
|
||||
static bool label_set_height_from_width(struct k3MEvent *ev, uint8_t *ud) {
|
||||
struct k3MLabel *this = (void*) ev->target;
|
||||
|
||||
int16_t pxsz[2];
|
||||
immdraw_font_size(this->font, this->sz, this->txt, this->w, pxsz);
|
||||
|
||||
this->h = pxsz[1];
|
||||
|
||||
return true;
|
||||
}
|
||||
struct k3MLabel *k3MLabel(struct k3Font *font, float sz, const char *txt) {
|
||||
struct k3MLabel *ret = calloc(1, sizeof(*ret));
|
||||
ret->font = font;
|
||||
@ -187,6 +287,9 @@ struct k3MLabel *k3MLabel(struct k3Font *font, float sz, const char *txt) {
|
||||
ret->txt = strdup(txt);
|
||||
|
||||
k3MRegisterEventHandler(ret, k3M_EVENT_DRAW, label_draw, NULL, 0);
|
||||
k3MRegisterEventHandler(ret, k3M_EVENT_MEASURE, label_measure, NULL, 0);
|
||||
k3MRegisterEventHandler(ret, k3M_EVENT_SET_HEIGHT_FROM_WIDTH, label_set_height_from_width, NULL, 0);
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -245,8 +348,12 @@ 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;
|
||||
struct k3MObj *innermost;
|
||||
|
||||
if(this->mouseCapture) {
|
||||
innermost = this->mouseCapture;
|
||||
} else {
|
||||
innermost = (struct k3MObj*) this;
|
||||
while(innermost->childCount != 0) {
|
||||
|
||||
bool foundInner = false;
|
||||
@ -271,8 +378,35 @@ static bool screen_ev(struct k3MEvent *ev, uint8_t *ud) {
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if(innermost != this->lastHover) {
|
||||
if(this->lastHover) {
|
||||
k3MEventSend(&(struct k3MEvent) {
|
||||
.code = k3M_EVENT_MOUSE_LEAVE,
|
||||
|
||||
.kind = k3M_EVENTKIND_DIRECT,
|
||||
|
||||
.original = ev->original,
|
||||
.target = this->lastHover,
|
||||
|
||||
.mouse = ev->mouse,
|
||||
});
|
||||
}
|
||||
|
||||
if(innermost != (void*) this) {
|
||||
k3MEventSend(&(struct k3MEvent) {
|
||||
.code = k3M_EVENT_MOUSE_ENTER,
|
||||
|
||||
.kind = k3M_EVENTKIND_DIRECT,
|
||||
|
||||
.original = ev->original,
|
||||
.target = innermost,
|
||||
|
||||
.mouse = ev->mouse,
|
||||
});
|
||||
}
|
||||
|
||||
this->lastHover->hovered = false;
|
||||
innermost->hovered = true;
|
||||
this->lastHover = innermost;
|
||||
@ -284,16 +418,22 @@ static bool screen_ev(struct k3MEvent *ev, uint8_t *ud) {
|
||||
this->keyboardFocus = innermost;
|
||||
}
|
||||
|
||||
ev->kind = k3M_EVENTKIND_BUBBLE;
|
||||
ev->target = innermost;
|
||||
k3MEventSend(ev);
|
||||
k3MEventSend(&(struct k3MEvent) {
|
||||
.code = ev->code,
|
||||
.kind = k3M_EVENTKIND_BUBBLE,
|
||||
.original = ev->original,
|
||||
.target = innermost,
|
||||
.mouse = ev->mouse,
|
||||
});
|
||||
|
||||
if(ev->code == k3M_EVENT_MOUSE_RELEASE) {
|
||||
ev->code = k3M_EVENT_MOUSE_CLICK;
|
||||
|
||||
ev->kind = k3M_EVENTKIND_DIRECT;
|
||||
ev->target = innermost;
|
||||
k3MEventSend(ev);
|
||||
k3MEventSend(&(struct k3MEvent) {
|
||||
.code = k3M_EVENT_MOUSE_CLICK,
|
||||
.kind = k3M_EVENTKIND_DIRECT,
|
||||
.original = ev->original,
|
||||
.target = innermost,
|
||||
.mouse = ev->mouse,
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@ -302,20 +442,25 @@ static bool screen_ev(struct k3MEvent *ev, uint8_t *ud) {
|
||||
} 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);
|
||||
k3MEventSend(&(struct k3MEvent) {
|
||||
.code = ev->code,
|
||||
.kind = k3M_EVENTKIND_BUBBLE,
|
||||
.original = ev->original,
|
||||
.target = this->keyboardFocus,
|
||||
.key = ev->key,
|
||||
});
|
||||
}
|
||||
|
||||
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)) {
|
||||
struct k3MEvent newev = *ev;
|
||||
newev.kind = k3M_EVENTKIND_CAPTURE;
|
||||
newev.target = this->children[i];
|
||||
if(k3MEventSend(&newev)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -323,39 +468,118 @@ static bool screen_ev(struct k3MEvent *ev, uint8_t *ud) {
|
||||
|
||||
return false;
|
||||
}
|
||||
static bool screen_arrange(struct k3MEvent *ev, uint8_t *ud) {
|
||||
struct k3MObj *this = ev->target;
|
||||
|
||||
for(size_t c = 0; c < this->childCount; c++) {
|
||||
struct k3MObj *child = this->children[c];
|
||||
|
||||
struct k3MProperty *left = k3MFindProperty(child, k3M_PROP_LEFT, true);
|
||||
if(left) {
|
||||
if(left->units[0] == k3M_UNIT_ABSOLUTE) {
|
||||
child->x = this->x + left->f[0];
|
||||
} else if(left->units[0] == k3M_UNIT_PROPORTION) {
|
||||
child->x = this->x + this->w * left->f[0];
|
||||
}
|
||||
}
|
||||
|
||||
struct k3MProperty *top = k3MFindProperty(child, k3M_PROP_TOP, true);
|
||||
if(top) {
|
||||
if(top->units[0] == k3M_UNIT_ABSOLUTE) {
|
||||
child->y = this->y + top->f[0];
|
||||
} else if(top->units[0] == k3M_UNIT_PROPORTION) {
|
||||
child->y = this->y + this->h * top->f[0];
|
||||
}
|
||||
}
|
||||
|
||||
struct k3MProperty *width = k3MFindProperty(child, k3M_PROP_WIDTH, true);
|
||||
if(width) {
|
||||
if(width->units[0] == k3M_UNIT_ABSOLUTE) {
|
||||
child->w = width->f[0];
|
||||
} else if(width->units[0] == k3M_UNIT_PROPORTION) {
|
||||
child->w = this->w * width->f[0];
|
||||
}
|
||||
}
|
||||
|
||||
struct k3MProperty *height = k3MFindProperty(child, k3M_PROP_HEIGHT, true);
|
||||
if(height) {
|
||||
if(height->units[0] == k3M_UNIT_ABSOLUTE) {
|
||||
child->h = height->f[0];
|
||||
} else if(height->units[0] == k3M_UNIT_PROPORTION) {
|
||||
child->h = this->h * height->f[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
struct k3MScreen *k3MScreen() {
|
||||
struct k3MScreen *ret = calloc(1, sizeof(*ret));
|
||||
|
||||
ret->lastHover = (void*) ret;
|
||||
|
||||
k3MRegisterEventHandler(ret, k3M_EVENT_ARRANGE, screen_arrange, NULL, 0);
|
||||
k3MRegisterEventHandler(ret, k3M_EVENT_ALL, screen_ev, NULL, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
bool k3MCaptureMouse(struct k3MScreen *screen, struct k3MObj *capt) {
|
||||
if(screen->mouseCapture) {
|
||||
return false;
|
||||
}
|
||||
|
||||
screen->mouseCapture = capt;
|
||||
|
||||
return true;
|
||||
}
|
||||
void k3MReleaseMouse(struct k3MScreen *screen) {
|
||||
screen->mouseCapture = NULL;
|
||||
}
|
||||
|
||||
static bool textbutton_draw(struct k3MEvent *ev, uint8_t *ud) {
|
||||
struct k3MTextButton *this = (void*) ev->target;
|
||||
|
||||
obj_draw((void*) this);
|
||||
obj_draw_direct((void*) this);
|
||||
|
||||
if(this->txt) {
|
||||
/*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});*/
|
||||
|
||||
int alignment = k3M_ALIGN_CENTER;
|
||||
|
||||
int ha = k3M_ALIGN_CENTER;
|
||||
struct k3MProperty *prop = k3MFindProperty(this, k3M_PROP_HORIZONTAL_ALIGNMENT, false);
|
||||
if(prop) alignment = prop->si[0];
|
||||
if(prop) ha = prop->si[0];
|
||||
|
||||
immdraw_font_draw(this->font, this->x, this->y, this->w, this->sz, strlen(this->txt), this->txt, alignment,
|
||||
int va = k3M_ALIGN_CENTER;
|
||||
prop = k3MFindProperty(this, k3M_PROP_VERTICAL_ALIGNMENT, false);
|
||||
if(prop) va = prop->si[0];
|
||||
|
||||
int16_t x = this->x;
|
||||
int16_t y = this->y;
|
||||
|
||||
if(va != k3M_ALIGN_TOP) {
|
||||
struct k3RectF txtsz;
|
||||
k3FontSz(this->font, this->sz, this->txt, this->w, &txtsz);
|
||||
if(va == k3M_ALIGN_CENTER) {
|
||||
y += (this->h - txtsz.h) / 2;
|
||||
} else if(va == k3M_ALIGN_BOTTOM) {
|
||||
y += this->h - txtsz.h;
|
||||
}
|
||||
}
|
||||
|
||||
immdraw_font_draw(this->font, x, y, this->w, this->sz, strlen(this->txt), this->txt, ha,
|
||||
1 - 0.8 * this->disabled, 1 - 0.8 * this->disabled, 1 - 0.8 * this->disabled, 1);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
static bool textbutton_measure(struct k3MEvent *ev, uint8_t *ud) {
|
||||
struct k3MTextButton *this = (void*) ev->target;
|
||||
|
||||
struct k3RectF sz = {};
|
||||
k3FontSz(this->font, this->sz, this->txt, -1, &sz);
|
||||
|
||||
this->w = ceilf(sz.w);
|
||||
this->h = ceilf(sz.h);
|
||||
|
||||
return false;
|
||||
}
|
||||
struct k3MTextButton *k3MTextButton(struct k3Font *font, float sz, const char *txt) {
|
||||
struct k3MTextButton *ret = calloc(1, sizeof(*ret));
|
||||
|
||||
@ -363,6 +587,7 @@ struct k3MTextButton *k3MTextButton(struct k3Font *font, float sz, const char *t
|
||||
ret->sz = sz;
|
||||
ret->txt = strdup(txt);
|
||||
|
||||
k3MRegisterEventHandler(ret, k3M_EVENT_MEASURE, textbutton_measure, NULL, 0);
|
||||
k3MRegisterEventHandler(ret, k3M_EVENT_DRAW, textbutton_draw, NULL, 0);
|
||||
|
||||
return ret;
|
||||
@ -371,7 +596,7 @@ struct k3MTextButton *k3MTextButton(struct k3Font *font, float sz, const char *t
|
||||
static bool textinput_draw(struct k3MEvent *ev, uint8_t *ud) {
|
||||
struct k3MTextInput *this = (void*) ev->target;
|
||||
|
||||
obj_draw((void*) this);
|
||||
obj_draw_direct((void*) this);
|
||||
|
||||
if(this->txt) {
|
||||
bool isPlaceholder = strlen(this->txt) == 0;
|
||||
@ -437,7 +662,174 @@ struct k3MTextInput *k3MTextInput(struct k3Font *font, float sz, const char *pla
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool obj_draw(struct k3MEvent *ev, uint8_t *ud) {
|
||||
obj_draw_direct(ev->target);
|
||||
return false;
|
||||
}
|
||||
struct k3MObj *k3MObj() {
|
||||
struct k3MObj *ret = calloc(1, sizeof(*ret));
|
||||
k3MRegisterEventHandler(ret, k3M_EVENT_DRAW, obj_draw, NULL, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool image_draw(struct k3MEvent *ev, uint8_t *ud) {
|
||||
struct k3MImage *this = (void*) ev->target;
|
||||
|
||||
struct k3MProperty *propFGColor = k3MFindProperty(ev->target, k3M_PROP_FG_COLOR, false);
|
||||
|
||||
vec4 color = {1, 1, 1, 1};
|
||||
if(propFGColor) {
|
||||
color[0] = propFGColor->si[0] / 255.0;
|
||||
color[1] = propFGColor->si[1] / 255.0;
|
||||
color[2] = propFGColor->si[2] / 255.0;
|
||||
color[3] = propFGColor->si[3] / 255.0;
|
||||
}
|
||||
|
||||
immdraw_image_draw(&this->data, this->x, this->y, this->w, this->h, color[0], color[1], color[2], color[3]);
|
||||
|
||||
return false;
|
||||
}
|
||||
struct k3MImage *k3MImage(k3MImageData data) {
|
||||
struct k3MImage *ret = calloc(1, sizeof(*ret));
|
||||
ret->data = data;
|
||||
k3MRegisterEventHandler(ret, k3M_EVENT_DRAW, image_draw, NULL, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define SCROLLBAR_WIDTH_DEFAULT 16
|
||||
static bool scrollbox_arrange(struct k3MEvent *ev, uint8_t *ud) {
|
||||
struct k3MScrollbox *this = (void*) ev->target;
|
||||
|
||||
struct k3MObj *contentBox = this->children[0];
|
||||
contentBox->x = this->x;
|
||||
contentBox->y = this->y;
|
||||
contentBox->w = this->w - 16;
|
||||
contentBox->h = 16384;
|
||||
|
||||
return false;
|
||||
}
|
||||
static bool scrollbox_post_arrange(struct k3MEvent *ev, uint8_t *ud) {
|
||||
struct k3MScrollbox *this = (void*) ev->target;
|
||||
|
||||
struct k3MObj *contentBox = this->children[0];
|
||||
|
||||
size_t maxY2 = 0;
|
||||
for(size_t c = 0; c < contentBox->childCount; c++) {
|
||||
size_t y2 = contentBox->children[c]->y + contentBox->children[c]->h;
|
||||
|
||||
if(maxY2 < y2) {
|
||||
maxY2 = y2;
|
||||
}
|
||||
}
|
||||
|
||||
contentBox->h = maxY2 - contentBox->y;
|
||||
|
||||
if(this->h > contentBox->h) {
|
||||
this->scrollbarLength = this->h;
|
||||
} else {
|
||||
this->scrollbarLength = this->h * this->h / contentBox->h;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
static bool scrollbox_draw(struct k3MEvent *ev, uint8_t *ud) {
|
||||
struct k3MScrollbox *this = (void*) ev->target;
|
||||
|
||||
int scrollbarWidth = SCROLLBAR_WIDTH_DEFAULT;
|
||||
struct k3MProperty *prop = k3MFindProperty(ev->target, k3M_PROP_SCROLLBAR_SIZE, false);
|
||||
if(prop) {
|
||||
scrollbarWidth = prop->si[0];
|
||||
}
|
||||
|
||||
immdraw_fill_rect(this->x + this->w - scrollbarWidth, this->y + this->scrollbarOffset, scrollbarWidth, this->scrollbarLength, 1, 1, 1, 1, 0);
|
||||
|
||||
return false;
|
||||
}
|
||||
static bool scrollbox_mouseshit(struct k3MEvent *ev, uint8_t *ud) {
|
||||
struct k3MScrollbox *this = (void*) ev->target;
|
||||
|
||||
if(ev->code == k3M_EVENT_MOUSE_PRESS) {
|
||||
if(k3MCaptureMouse((struct k3MScreen*) ev->original, this)) {
|
||||
|
||||
struct k3MProperty *prop = k3MFindProperty(ev->target, k3M_PROP_SCROLL_ANYWHERE, false);
|
||||
bool scrollAnywhere = prop ? prop->si[0] : false;
|
||||
|
||||
int scrollbarWidth = SCROLLBAR_WIDTH_DEFAULT;
|
||||
prop = k3MFindProperty(ev->target, k3M_PROP_SCROLLBAR_SIZE, false);
|
||||
if(prop) {
|
||||
scrollbarWidth = prop->si[0];
|
||||
}
|
||||
|
||||
if(ev->mouse.x >= this->x + this->w - scrollbarWidth) {
|
||||
this->mouseHeld = 1;
|
||||
} else if(scrollAnywhere) {
|
||||
this->mouseHeld = 2;
|
||||
} else {
|
||||
this->mouseHeld = 0;
|
||||
}
|
||||
|
||||
this->mouseX = ev->mouse.x;
|
||||
this->mouseY = ev->mouse.y;
|
||||
|
||||
return !!this->mouseHeld;
|
||||
}
|
||||
} else if(ev->code == k3M_EVENT_MOUSE_RELEASE) {
|
||||
if(this->mouseHeld) {
|
||||
this->mouseHeld = false;
|
||||
k3MReleaseMouse((struct k3MScreen*) ev->original);
|
||||
|
||||
return true;
|
||||
}
|
||||
} else if(ev->code == k3M_EVENT_MOUSE_MOTION) {
|
||||
if(this->mouseHeld) {
|
||||
|
||||
int16_t diffX = ev->mouse.x - this->mouseX;
|
||||
int16_t diffY = ev->mouse.y - this->mouseY;
|
||||
this->mouseX = ev->mouse.x;
|
||||
this->mouseY = ev->mouse.y;
|
||||
|
||||
struct k3MObj *contentBox = this->children[0];
|
||||
|
||||
if(this->mouseHeld == 1) {
|
||||
this->scrollbarOffset += diffY;
|
||||
contentBox->y = (float) this->y + this->scrollbarOffset * (-contentBox->h + this->h) / (this->h - this->scrollbarLength);
|
||||
} else if(this->mouseHeld == 2) {
|
||||
contentBox->y += diffY;
|
||||
}
|
||||
|
||||
if(contentBox->y > this->y) {
|
||||
contentBox->y = this->y;
|
||||
} else if(contentBox->y < this->y - contentBox->h + this->h) {
|
||||
contentBox->y = this->y - contentBox->h + this->h;
|
||||
}
|
||||
this->scrollbarOffset = (float) (contentBox->y - this->y) * (this->h - this->scrollbarLength) / (this->h - contentBox->h);
|
||||
|
||||
k3MArrange(contentBox);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
struct k3MScrollbox *k3MScrollbox() {
|
||||
struct k3MScrollbox *this = calloc(1, sizeof(*this));
|
||||
|
||||
struct k3MObj *contentBox = k3MObj();
|
||||
k3MAddChild(this, contentBox);
|
||||
|
||||
k3MRegisterEventHandler(this, k3M_EVENT_ARRANGE, scrollbox_arrange, NULL, 0);
|
||||
k3MRegisterEventHandler(this, k3M_EVENT_POST_ARRANGE, scrollbox_post_arrange, NULL, 0);
|
||||
k3MRegisterEventHandler(this, k3M_EVENT_DRAW, scrollbox_draw, NULL, 0);
|
||||
k3MRegisterEventHandler(this, k3M_EVENT_MOUSE_PRESS, scrollbox_mouseshit, NULL, 0);
|
||||
k3MRegisterEventHandler(this, k3M_EVENT_MOUSE_MOTION, scrollbox_mouseshit, NULL, 0);
|
||||
k3MRegisterEventHandler(this, k3M_EVENT_MOUSE_RELEASE, scrollbox_mouseshit, NULL, 0);
|
||||
|
||||
this->crop = true;
|
||||
|
||||
return this;
|
||||
}
|
||||
struct k3MObj *k3MScrollboxGetContent(struct k3MScrollbox *this) {
|
||||
return this->children[0];
|
||||
}
|
||||
|
58
src/k3menu.h
58
src/k3menu.h
@ -21,7 +21,9 @@ struct k3MObj;
|
||||
#define k3M_EVENT_COMPLETE 10
|
||||
#define k3M_EVENT_MEASURE 11
|
||||
#define k3M_EVENT_ARRANGE 12
|
||||
#define k3M_EVENT_ALL 13
|
||||
#define k3M_EVENT_POST_ARRANGE 13
|
||||
#define k3M_EVENT_SET_HEIGHT_FROM_WIDTH 14
|
||||
#define k3M_EVENT_ALL 15
|
||||
|
||||
#define k3M_MOUSE_BUTTON_0 0
|
||||
#define k3M_MOUSE_BUTTON_1 1
|
||||
@ -31,11 +33,18 @@ struct k3MObj;
|
||||
#define k3M_EVENTKIND_CAPTURE 1
|
||||
#define k3M_EVENTKIND_BUBBLE 2
|
||||
|
||||
#define k3M_USERDATA_SIZE 16
|
||||
#define k3M_USERDATA_SIZE 32
|
||||
|
||||
#define k3M_ALIGN_LEFT 0
|
||||
#define k3M_ALIGN_TOP 3
|
||||
#define k3M_ALIGN_CENTER 1
|
||||
#define k3M_ALIGN_RIGHT 2
|
||||
#define k3M_ALIGN_BOTTOM 4
|
||||
|
||||
#define k3M_IDX_TOP 0
|
||||
#define k3M_IDX_RIGHT 1
|
||||
#define k3M_IDX_BOTTOM 2
|
||||
#define k3M_IDX_LEFT 3
|
||||
|
||||
#ifdef k3M_FIXED_POINT
|
||||
typedef uint8_t k3MCC;
|
||||
@ -43,6 +52,11 @@ typedef uint8_t k3MCC;
|
||||
typedef float k3MCC;
|
||||
#endif
|
||||
|
||||
#define k3M_UNIT_ABSOLUTE 0
|
||||
#define k3M_UNIT_PROPORTION 1
|
||||
|
||||
#include"k3menu_internal.h"
|
||||
|
||||
struct k3MEvent {
|
||||
uint16_t code;
|
||||
|
||||
@ -76,16 +90,28 @@ typedef struct k3MEventHandler {
|
||||
|
||||
enum k3MPropertyType {
|
||||
k3M_PROP_BG_COLOR,
|
||||
k3M_PROP_FG_COLOR,
|
||||
k3M_PROP_BORDER_RADIUS,
|
||||
k3M_PROP_MARGIN,
|
||||
k3M_PROP_PADDING,
|
||||
k3M_PROP_HORIZONTAL_ALIGNMENT,
|
||||
k3M_PROP_VERTICAL_ALIGNMENT,
|
||||
k3M_PROP_LEFT,
|
||||
k3M_PROP_TOP,
|
||||
k3M_PROP_WIDTH,
|
||||
k3M_PROP_HEIGHT,
|
||||
k3M_PROP_FONT_SIZE,
|
||||
k3M_PROP_SCROLL_ANYWHERE,
|
||||
k3M_PROP_SCROLLBAR_SIZE,
|
||||
};
|
||||
struct k3MProperty {
|
||||
enum k3MPropertyType type;
|
||||
uint8_t units[4];
|
||||
union {
|
||||
intmax_t si[4];
|
||||
void *ptr;
|
||||
void *ptr[4];
|
||||
uint8_t buf[32];
|
||||
float f[4];
|
||||
};
|
||||
};
|
||||
|
||||
@ -103,7 +129,7 @@ struct k3MObj {
|
||||
int16_t wDesired;
|
||||
int16_t hDesired;
|
||||
|
||||
bool invisible, hovered, disabled;
|
||||
bool invisible, hovered, disabled, crop;
|
||||
|
||||
k3MEventHandler *handlers;
|
||||
size_t handlerCount;
|
||||
@ -150,8 +176,12 @@ struct k3MScreen {
|
||||
|
||||
struct k3MObj *keyboardFocus;
|
||||
struct k3MObj *lastHover;
|
||||
|
||||
struct k3MObj *mouseCapture;
|
||||
};
|
||||
struct k3MScreen *k3MScreen();
|
||||
bool k3MCaptureMouse(struct k3MScreen*, struct k3MObj*);
|
||||
void k3MReleaseMouse(struct k3MScreen*);
|
||||
|
||||
struct k3MTextButton {
|
||||
struct k3MObj;
|
||||
@ -173,3 +203,23 @@ struct k3MTextInput {
|
||||
char *txt;
|
||||
};
|
||||
struct k3MTextInput *k3MTextInput(struct k3Font *font, float sz, const char *placeholder, const char *txt);
|
||||
|
||||
struct k3MImage {
|
||||
struct k3MObj;
|
||||
|
||||
k3MImageData data;
|
||||
};
|
||||
struct k3MImage *k3MImage(k3MImageData);
|
||||
|
||||
struct k3MScrollbox {
|
||||
struct k3MObj;
|
||||
|
||||
int mouseHeld;
|
||||
int16_t mouseX;
|
||||
int16_t mouseY;
|
||||
|
||||
float scrollbarOffset;
|
||||
int16_t scrollbarLength;
|
||||
};
|
||||
struct k3MScrollbox *k3MScrollbox();
|
||||
struct k3MObj *k3MScrollboxGetContent(struct k3MScrollbox*);
|
||||
|
@ -67,10 +67,10 @@ static void random_cone_vector(float coneAngle, vec3 output) {
|
||||
}
|
||||
|
||||
static void regenerate_model(struct k3CPUQuadParticles *this, vec3 cameraRight, vec3 cameraUp, vec3 cameraFront) {
|
||||
vec3 *vpos = calloc(sizeof(*vpos), 4 * this->capacity);
|
||||
uint8_t *vcols = calloc(4, 4 * this->capacity);
|
||||
vec2 *vuvs = calloc(sizeof(*vuvs), 4 * this->capacity);
|
||||
uint8_t *vnrms = calloc(3, 4 * this->capacity);
|
||||
vec3 *vpos = _mm_malloc(sizeof(*vpos) * 4 * this->capacity, 16);
|
||||
uint8_t *vcols = _mm_malloc(4 * 4 * this->capacity, 16);
|
||||
vec2 *vuvs = _mm_malloc(sizeof(*vuvs) * 4 * this->capacity, 16);
|
||||
uint8_t *vnrms = _mm_malloc(3 * 4 * this->capacity, 16);
|
||||
|
||||
vec3 halfRight, halfUp;
|
||||
glm_vec3_scale(cameraRight, 0.5, halfRight);
|
||||
@ -128,10 +128,10 @@ static void regenerate_model(struct k3CPUQuadParticles *this, vec3 cameraRight,
|
||||
|
||||
this->mdl->meshes[0].idxNumber = this->count * 6;
|
||||
|
||||
free(vpos);
|
||||
free(vcols);
|
||||
free(vuvs);
|
||||
free(vnrms);
|
||||
_mm_free(vpos);
|
||||
_mm_free(vcols);
|
||||
_mm_free(vuvs);
|
||||
_mm_free(vnrms);
|
||||
}
|
||||
|
||||
static void copy_particle(struct k3CPUQuadParticles *this, size_t from, size_t to) {
|
||||
|
@ -5,6 +5,19 @@
|
||||
#include"k3.h"
|
||||
|
||||
struct k3CPUQuadParticles {
|
||||
vec4 colorStart;
|
||||
vec4 colorEnd;
|
||||
|
||||
vec3 origin;
|
||||
vec3 gravity;
|
||||
vec3 emissionConeDirection;
|
||||
float emissionRate;
|
||||
float emissionConeAngle;
|
||||
float particleLifetime;
|
||||
|
||||
bool emissionEnabled;
|
||||
float emissionLifetime;
|
||||
|
||||
size_t capacity;
|
||||
size_t count;
|
||||
vec3 *positions;
|
||||
@ -13,19 +26,6 @@ struct k3CPUQuadParticles {
|
||||
float *lifetimes;
|
||||
|
||||
struct k3Mdl *mdl;
|
||||
|
||||
vec4 colorStart;
|
||||
vec4 colorEnd;
|
||||
|
||||
vec3 origin;
|
||||
vec3 gravity;
|
||||
float emissionRate;
|
||||
vec3 emissionConeDirection;
|
||||
float emissionConeAngle;
|
||||
float particleLifetime;
|
||||
|
||||
bool emissionEnabled;
|
||||
float emissionLifetime;
|
||||
};
|
||||
|
||||
void k3CPUQuadParticlesInit(struct k3CPUQuadParticles*, struct k3Mat*);
|
||||
|
Loading…
Reference in New Issue
Block a user