Compare commits

..

No commits in common. "4d74b5e3e9a597a63d6a3e38143e2ec8382e8ac7" and "a06aacd405e06f36a0eb7a878a3104b679c9bd6f" have entirely different histories.

13 changed files with 386 additions and 3219 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,82 +0,0 @@
// File: bc7enc.h - Richard Geldreich, Jr. - MIT license or public domain (see end of bc7enc.c)
#include <stdlib.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#define BC7ENC_BLOCK_SIZE (16)
#define BC7ENC_MAX_PARTITIONS1 (64)
#define BC7ENC_MAX_UBER_LEVEL (4)
typedef uint8_t bc7enc_bool;
#define BC7ENC_TRUE (1)
#define BC7ENC_FALSE (0)
typedef struct
{
// m_max_partitions_mode may range from 0 (disables mode 1) to BC7ENC_MAX_PARTITIONS1. The higher this value, the slower the compressor, but the higher the quality.
uint32_t m_max_partitions_mode;
// Relative RGBA or YCbCrA weights.
uint32_t m_weights[4];
// m_uber_level may range from 0 to BC7ENC_MAX_UBER_LEVEL. The higher this value, the slower the compressor, but the higher the quality.
uint32_t m_uber_level;
// If m_perceptual is true, colorspace error is computed in YCbCr space, otherwise RGB.
bc7enc_bool m_perceptual;
// Set m_try_least_squares to false for slightly faster/lower quality compression.
bc7enc_bool m_try_least_squares;
// When m_mode_partition_estimation_filterbank, the mode1 partition estimator skips lesser used partition patterns unless they are strongly predicted to be potentially useful.
// There's a slight loss in quality with this enabled (around .08 dB RGB PSNR or .05 dB Y PSNR), but up to a 11% gain in speed depending on the other settings.
bc7enc_bool m_mode_partition_estimation_filterbank;
bc7enc_bool m_use_mode5_for_alpha;
bc7enc_bool m_use_mode7_for_alpha;
} bc7enc_compress_block_params;
inline static void bc7enc_compress_block_params_init_linear_weights(bc7enc_compress_block_params *p)
{
p->m_perceptual = BC7ENC_FALSE;
p->m_weights[0] = 1;
p->m_weights[1] = 1;
p->m_weights[2] = 1;
p->m_weights[3] = 1;
}
inline static void bc7enc_compress_block_params_init_perceptual_weights(bc7enc_compress_block_params *p)
{
p->m_perceptual = BC7ENC_TRUE;
p->m_weights[0] = 128;
p->m_weights[1] = 64;
p->m_weights[2] = 16;
p->m_weights[3] = 32;
}
inline static void bc7enc_compress_block_params_init(bc7enc_compress_block_params *p)
{
p->m_max_partitions_mode = BC7ENC_MAX_PARTITIONS1;
p->m_try_least_squares = BC7ENC_TRUE;
p->m_mode_partition_estimation_filterbank = BC7ENC_TRUE;
p->m_uber_level = 0;
p->m_use_mode5_for_alpha = BC7ENC_TRUE;
p->m_use_mode7_for_alpha = BC7ENC_TRUE;
bc7enc_compress_block_params_init_perceptual_weights(p);
}
// bc7enc_compress_block_init() MUST be called before calling bc7enc_compress_block() (or you'll get artifacts).
void bc7enc_compress_block_init();
// Packs a single block of 16x16 RGBA pixels (R first in memory) to 128-bit BC7 block pBlock, using either mode 1 and/or 6.
// Alpha blocks will always use mode 6, and by default opaque blocks will use either modes 1 or 6.
// Returns BC7ENC_TRUE if the block had any pixels with alpha < 255, otherwise it return BC7ENC_FALSE. (This is not an error code - a block is always encoded.)
bc7enc_bool bc7enc_compress_block(void *pBlock, const void *pPixelsRGBA, const bc7enc_compress_block_params *pComp_params);
#ifdef __cplusplus
}
#endif

508
src/k3.c
View File

@ -1,4 +1,4 @@
#include"k3_internal.h"
#include"k3.h"
#include"gl.h"
@ -15,23 +15,41 @@
#include"ssort.h"
#define GL_FROM_K3TEX(k3t) ((k3t) ? (k3t)->tex : 0)
#define GL_FROM_K3MARCHER(k3m) ((GLuint) (uintptr_t) (k3m))
#define GL_FROM_K3ARBVP(k3m) ((GLuint) (uintptr_t) (k3m))
#define GL_FROM_K3ARBFP(k3m) ((GLuint) (uintptr_t) (k3m))
#define GL_FROM_K3GLSL(k3m) ((GLuint) (uintptr_t) (k3m))
#define RAST_DIFF 0
#define RAST_NORM 1
#define RAST_DISP 2
#define RAST_LEVELS 3
bool k3IsSoftSkinning = 0;
bool k3IsCore = 0;
static int k3CPUSkinning = 0;
int k3IsCore = 0;
static struct k3GLSLP *basicBlitProgram;
static struct k3GLSLP *basicCubemapProgram;
typedef void*(*TextureOfflineCompressorFunc)(const void *pixels, uint16_t width, uint16_t height, GLenum externalFmt, GLenum intype, size_t *compressedSize);
struct k3Tex {
GLuint tex;
int cubemap;
uint32_t szX;
uint32_t szY;
uint32_t szZ;
};
static bool TextureCompressionEnabled;
static GLenum TextureCompressionRGBA;
static GLenum TextureCompressionSRGBA;
static TextureOfflineCompressorFunc TextureOfflineCompressor;
struct k3Storage {
int16_t ref;
void(*free)(struct k3Storage*);
};
struct k3StorageBasic {
struct k3Storage;
GLuint gl;
};
void k3StorageRef(struct k3Storage *s) {
s->ref++;
@ -55,6 +73,40 @@ struct k3StorageBasic *k3StorageBasic() {
return ret;
}
struct k3Offscreen {
GLuint fbo;
struct k3Tex *diffuse;
struct k3Tex *depth;
};
struct k3Mdl {
struct {
vec3 *pos;
uint8_t *boneids;
uint16_t *boneweights;
} cpuSkinning;
size_t verts;
struct k3StorageBasic *vstore;
struct k3StorageBasic *estore;
uint16_t meshCount;
struct k3Mesh *meshes;
size_t boneCount;
mat4 *invBind;
uint8_t *boneParents;
uint16_t animCount;
struct k3Animation **anims;
vec3 aabb[2];
int offV, offN, offC, offU, offB, offT;
const char *debugname;
};
static uint16_t MainWidth, MainHeight;
void k3Resize(uint16_t width, uint16_t height) {
MainWidth = width;
@ -67,12 +119,6 @@ void k3SetTime(float t) {
}
static void update_aabb(struct k3Mdl *mdl, vec3 *pos) {
if(pos == k3_ATTRIB_NONE || pos == k3_ATTRIB_EMPTY || mdl->verts == 0) {
glm_vec3_zero(mdl->aabb[0]);
glm_vec3_zero(mdl->aabb[1]);
return;
}
glm_vec3_copy(pos[0], mdl->aabb[0]);
glm_vec3_copy(pos[0], mdl->aabb[1]);
for(size_t i = 0; i < mdl->verts; i++) {
@ -166,7 +212,7 @@ struct k3Mdl *k3MdlCreate(size_t verts, size_t indices, size_t boneCount, vec3 *
ret->animCount = 0;
ret->anims = NULL;
if(k3IsSoftSkinning && pos && boneids && boneweights) {
if(k3CPUSkinning && pos && boneids && boneweights) {
ret->cpuSkinning.pos = malloc(sizeof(*ret->cpuSkinning.pos) * verts);
memcpy(ret->cpuSkinning.pos, pos, sizeof(*ret->cpuSkinning.pos) * verts);
@ -195,44 +241,35 @@ struct k3Mdl *k3MdlCreate(size_t verts, size_t indices, size_t boneCount, vec3 *
int o = 0;
ret->offV = o;
if(pos != k3_ATTRIB_EMPTY) {
glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, o, 12 * verts, pos);
}
o += 12 * verts;
if(nrm) {
ret->offN = o;
if(nrm != k3_ATTRIB_EMPTY) {
glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, o, 3 * verts, nrm);
}
o += 3 * verts;
} else ret->offN = -1;
if(uvs) {
ret->offU = o;
if(uvs != k3_ATTRIB_EMPTY) {
glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, o, 8 * verts, uvs);
}
o += 8 * verts;
} else ret->offU = -1;
if(nrm && uvs) {
ret->offT = o;
if(nrm != k3_ATTRIB_EMPTY && uvs != k3_ATTRIB_EMPTY) {
int8_t *tans = generate_tangents(verts, indices, inds, pos, nrm, uvs);
glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, o, 3 * verts, tans);
free(tans);
}
o += 3 * verts;
} else ret->offT = -1;
if(cols) {
ret->offC = o;
if(cols != k3_ATTRIB_EMPTY) {
glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, o, 4 * verts, cols);
}
o += 4 * verts;
} else ret->offC = -1;
@ -247,9 +284,7 @@ struct k3Mdl *k3MdlCreate(size_t verts, size_t indices, size_t boneCount, vec3 *
} else ret->offB = -1;
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, ret->estore->gl);
if(inds && inds != k3_ATTRIB_EMPTY) {
glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, indices * sizeof(uint16_t), inds, GL_STATIC_DRAW_ARB);
}
update_aabb(ret, pos);
@ -404,11 +439,6 @@ static void anim_update(struct k3Animator *anim) {
void k3AnimatorSet(struct k3Animator *anim, float time) {
if(!anim->inter) anim->inter = _mm_malloc(sizeof(mat4) * anim->base->boneCount * anim->base->frameCount, 16);
if(!anim->loop) {
time = fmaxf(time, 0);
time = fminf(time, (float) (anim->base->frameCount - 1) / anim->base->fps);
}
anim->time = time;
anim_update(anim);
@ -450,7 +480,6 @@ void k3TexUpdate(struct k3Tex *tex, enum k3TexType type, int index, uint16_t wid
GLint internalFmt, externalFmt, intype;
int linearFilter, mipmap;
int compressed = 0;
switch(type) {
case k3_RAWCOLOR:
@ -461,8 +490,7 @@ void k3TexUpdate(struct k3Tex *tex, enum k3TexType type, int index, uint16_t wid
mipmap = 1;
break;
case k3_NORMAL:
compressed = TextureCompressionEnabled;
internalFmt = compressed ? TextureCompressionRGBA : GL_RGBA;
internalFmt = GL_RGBA;
externalFmt = GL_RGBA;
intype = GL_UNSIGNED_BYTE;
linearFilter = 1;
@ -470,9 +498,8 @@ void k3TexUpdate(struct k3Tex *tex, enum k3TexType type, int index, uint16_t wid
break;
case k3_DIFFUSE:
case k3_EMISSION:
compressed = TextureCompressionEnabled;
internalFmt = compressed
? (GLAD_GL_EXT_texture_sRGB ? TextureCompressionSRGBA : TextureCompressionRGBA)
internalFmt = GLAD_GL_EXT_texture_compression_s3tc
? (GLAD_GL_EXT_texture_sRGB ? GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT : GL_COMPRESSED_RGBA_S3TC_DXT5_EXT)
: (GLAD_GL_EXT_texture_sRGB ? GL_SRGB8_ALPHA8_EXT : GL_RGBA8);
externalFmt = GL_RGBA;
intype = GL_UNSIGNED_BYTE;
@ -495,7 +522,7 @@ void k3TexUpdate(struct k3Tex *tex, enum k3TexType type, int index, uint16_t wid
mipmap = 1;
break;
case k3_DEPTH:
internalFmt = GL_DEPTH_COMPONENT32F;
internalFmt = GL_DEPTH_COMPONENT24;
externalFmt = GL_DEPTH_COMPONENT;
intype = GL_UNSIGNED_INT;
if(!k3IsCore) glTexParameteri(target, GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE);
@ -517,9 +544,12 @@ void k3TexUpdate(struct k3Tex *tex, enum k3TexType type, int index, uint16_t wid
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
} else {
if(!k3IsCore && mipmap) {
glTexParameteri(target, GL_GENERATE_MIPMAP, GL_TRUE);
if(!k3IsCore && !mipmap) {
glTexParameteri(target, GL_GENERATE_MIPMAP, GL_FALSE);
} else {
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
if(type == k3_DEPTH) {
@ -527,18 +557,13 @@ void k3TexUpdate(struct k3Tex *tex, enum k3TexType type, int index, uint16_t wid
glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
}
if(!tex->cubemap && mipmap) {
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, linearFilter ? GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_LINEAR);
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, linearFilter ? GL_LINEAR : GL_NEAREST);
} else {
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, linearFilter ? GL_LINEAR : GL_NEAREST);
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, linearFilter ? GL_LINEAR : GL_NEAREST);
}
} else {
glBindTexture(target, tex->tex);
}
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, linearFilter ? GL_LINEAR : GL_NEAREST);
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, linearFilter ? GL_LINEAR : GL_NEAREST);
if(k3IsCore && type == k3_ALPHA) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_ONE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_ONE);
@ -552,16 +577,7 @@ void k3TexUpdate(struct k3Tex *tex, enum k3TexType type, int index, uint16_t wid
k3Log(k3_WARN, "Non-zero index passed for non-cubemap texture");
}
if(compressed && TextureOfflineCompressor) {
size_t len;
data = TextureOfflineCompressor(data, width, height, externalFmt, intype, &len);
glCompressedTexImage2D(target, 0, internalFmt, width, height, 0, len, data);
free(data);
} else {
glTexImage2D(target, 0, internalFmt, width, height, 0, externalFmt, intype, data);
}
if(!tex->cubemap && k3IsCore && mipmap) {
glGenerateMipmap(target);
@ -570,8 +586,6 @@ void k3TexUpdate(struct k3Tex *tex, enum k3TexType type, int index, uint16_t wid
tex->szX = width;
tex->szY = height;
tex->szZ = 0;
tex->glInternalFormat = internalFmt;
}
uint32_t k3TexSzX(struct k3Tex *this) {
return this->szX;
@ -589,16 +603,6 @@ static struct k3Light *Lights;
void k3SetLights(size_t count, struct k3Light *lightsNew) {
LightCount = count;
Lights = lightsNew;
for(int i = 0; i < count; i++) {
if(Lights[i].type == k3_DIRECTIONAL) {
if(Lights[i].dir.cascadeCount == 0) {
Lights[i].dir.cascadeCount = 1;
} else if(Lights[i].dir.cascadeCount > 3) {
Lights[i].dir.cascadeCount = 3;
}
}
}
}
struct k3Light *k3GetLights(size_t *a) {
@ -632,18 +636,15 @@ static mat4 CamMat;
static mat4 ProjMat;
struct LightShadow {
uint8_t vpCount;
mat4 vp[6];
mat4 vp;
vec4 atlasSegment;
#ifdef k3_IRREGULAR_SHADOWS
GLuint multimapEls; // buffer
GLuint multimapHeads; // image
#endif
} __attribute__((aligned(16)));
static size_t LightShadowsCount, LightShadowsCapacity;
static struct LightShadow *LightShadows;
static size_t LightShadowsCount = 0, LightShadowsCapacity = 0;
static struct k3Offscreen *ShadowAtlas;
static bool LightShadowIrregularMode = false;
@ -836,22 +837,17 @@ static void setup_glsl_lighting_uniforms(GLuint bound, int lightsStart, int ligh
lightsCount = LightCount - lightsStart;
}
if(lightsCount) {
// raise(SIGINT);
}
vec4 settings1[4];
vec4 settings2[4];
vec4 settings1[4] = {};
vec4 settings2[4] = {};
vec4 colors[4] = {};
vec4 colors[4];
memset(colors, 0, sizeof(colors));
for(int i = 0; i < lightsCount; i++) {
struct k3Light *l = &Lights[i + lightsStart];
if(l->type == k3_DIRECTIONAL) {
glm_vec4_copy(l->dir.direction, settings1[i]);
settings2[i][0] = l->dir.cascadeCount;
} else if(l->type == k3_SPOT) {
glm_vec4_copy(l->spot.position, settings1[i]);
@ -902,26 +898,20 @@ static void setup_glsl_shadow_uniforms(GLuint bound, int atlasUnit, int lightsSt
k3Log(k3_ERR, "Max 4 lights per pass");
}
if(!ShadowAtlas) return;
if(!LightShadows) return;
if(LightShadowIrregularMode) {
assert(k3IsCore);
glUniform1i(glGetUniformLocation(bound, "u_pixelsinshadow"), 0);
} else {
size_t vpi = 0;
mat4 m[6];
mat4 m[4];
memset(m, 0, sizeof(m));
vec4 seg[4];
for(int i = 0; i < lightsCount; i++) {
for(int z = 0; z < LightShadows[i + lightsStart].vpCount; z++) {
glm_mat4_copy(LightShadows[i + lightsStart].vp[z], m[vpi]);
vpi++;
}
glm_mat4_copy(LightShadows[i + lightsStart].vp, m[i]);
glm_vec4_copy(LightShadows[i + lightsStart].atlasSegment, seg[i]);
}
@ -934,12 +924,12 @@ static void setup_glsl_shadow_uniforms(GLuint bound, int atlasUnit, int lightsSt
}
if(!k3IsCore) {
glUniformMatrix4fvARB(glGetUniformLocationARB(bound, "u_shadows0vp"), vpi, GL_FALSE, (float*) m);
glUniformMatrix4fvARB(glGetUniformLocationARB(bound, "u_shadows0vp"), 4, GL_FALSE, (float*) m);
glUniform4fvARB(glGetUniformLocationARB(bound, "u_shadows0seg"), 4, (float*) seg);
glUniform1iARB(glGetUniformLocationARB(bound, "u_shadows0atlas"), atlasUnit);
} else {
glUniformMatrix4fv(glGetUniformLocationARB(bound, "u_shadows0vp"), vpi, GL_FALSE, (float*) m);
glUniformMatrix4fv(glGetUniformLocationARB(bound, "u_shadows0vp"), 4, GL_FALSE, (float*) m);
glUniform4fv(glGetUniformLocationARB(bound, "u_shadows0seg"), 4, (float*) seg);
glUniform1i(glGetUniformLocationARB(bound, "u_shadows0atlas"), atlasUnit);
@ -982,6 +972,7 @@ static int bind_shadow_texture(int textureUnit) {
}
static void enable_glsl_bones(GLuint bound, struct k3Mdl *mdl, struct k3AnimationBone *bones) {
if(mdl->boneCount) {
GLint a0;
GLint a1;
@ -998,7 +989,6 @@ static void enable_glsl_bones(GLuint bound, struct k3Mdl *mdl, struct k3Animatio
}
if(a0 != -1) {
if(bones) {
if(!k3IsCore) {
glEnableVertexAttribArrayARB(a0);
glEnableVertexAttribArrayARB(a1);
@ -1010,15 +1000,6 @@ static void enable_glsl_bones(GLuint bound, struct k3Mdl *mdl, struct k3Animatio
glVertexAttribPointer(a0, 4, GL_UNSIGNED_BYTE, GL_FALSE, 0, (void*) (mdl->offB + 0 * mdl->verts));
glVertexAttribPointer(a1, 4, GL_UNSIGNED_SHORT, GL_TRUE, 0, (void*) (mdl->offB + 4 * mdl->verts));
}
} else {
if(!k3IsCore) {
glVertexAttrib4fARB(a0, 0, 0, 0, 0);
glVertexAttrib4fARB(a1, 1, 0, 0, 0);
} else {
glVertexAttrib4f(a0, 0, 0, 0, 0);
glVertexAttrib4f(a1, 1, 0, 0, 0);
}
}
}
if(bones) {
@ -1040,8 +1021,10 @@ static void enable_glsl_bones(GLuint bound, struct k3Mdl *mdl, struct k3Animatio
}
}
}
}
static void disable_glsl_bones(struct k3Mdl *mdl, GLuint bound) {
if(mdl->boneCount) {
GLint a0;
GLint a1;
@ -1058,6 +1041,7 @@ static void disable_glsl_bones(struct k3Mdl *mdl, GLuint bound) {
}
}
}
}
static void enable_glsl_tangents(GLuint bound, struct k3Mdl *mdl) {
if(mdl->offT == -1) {
@ -1316,7 +1300,6 @@ static void forward_subpass(mat4 view, int transparent, int lightsStart, int lig
GLuint lastVP = 0, lastFP = 0;
struct k3Mat *lastMaterial = NULL;
int lastAdditive = -1;
int lastDepthwrite = -1;
for(size_t rble = rbleStart; rble < rbleEnd; rble++) {
struct k3Mdl *mdl = renderQueue[rble].mdl;
@ -1363,15 +1346,6 @@ static void forward_subpass(mat4 view, int transparent, int lightsStart, int lig
lastAdditive = mat->passes[0].additive;
}
if(lastDepthwrite != mat->passes[0].depthwrite) {
lastDepthwrite = mat->passes[0].depthwrite;
if(lastDepthwrite) {
glDepthMask(GL_TRUE);
} else {
glDepthMask(GL_FALSE);
}
}
if(glsl) {
if(lastGLSL != glsl) {
if(k3IsCore)
@ -1481,7 +1455,7 @@ static void forward_subpass(mat4 view, int transparent, int lightsStart, int lig
enable_glsl_tangents(glsl, mdl);
}
if(k3IsSoftSkinning) {
if(k3CPUSkinning) {
apply_cpu_skinning(mdl, bones);
}
@ -1516,6 +1490,7 @@ void k3PassForward(mat4 projection, mat4 cam) {
glEnable(GL_DEPTH_TEST);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glDepthMask(GL_TRUE);
glDepthFunc(GL_LEQUAL);
if(GLAD_GL_EXT_framebuffer_sRGB) {
@ -1529,8 +1504,6 @@ void k3PassForward(mat4 projection, mat4 cam) {
if(!k3IsCore) {
glEnable(GL_NORMALIZE);
glEnable(GL_COLOR_MATERIAL);
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
}
int l = 0, k = LightCount;
@ -1666,7 +1639,9 @@ void k3PassDepthOnly(mat4 projection, mat4 cam, int clear, int cull) {
enable_glsl_bones(glsl, mdl, bones);
}
if(k3IsSoftSkinning) {
enable_vertex_buffers(mdl, glsl);
if(k3CPUSkinning) {
apply_cpu_skinning(mdl, bones);
}
@ -1688,46 +1663,27 @@ void k3PassDepthOnly(mat4 projection, mat4 cam, int clear, int cull) {
glFrontFace(GL_CCW);
}
static void split_frustum(mat4 proj, int cascades, mat4 croppeds[]) {
float fovy = glm_persp_fovy(proj);
float aspect = glm_persp_aspect(proj);
static size_t compute_light_views(mat4 **_projs, mat4 **_cams, char **_isCube) {
mat4 *projs = _mm_malloc(sizeof(*projs) * LightCount * 6, 16);
mat4 *cams = _mm_malloc(sizeof(*cams) * LightCount * 6, 16);
char *isCube = _mm_malloc(sizeof(*isCube) * LightCount * 6, 1);
float near, far;
glm_persp_decomp_near(proj, &near);
glm_persp_decomp_far(proj, &far);
float depthChunk = (far - near) / cascades;
for(int c = 0; c < cascades; c++) {
glm_perspective(fovy, aspect, near + c * depthChunk, near + (c + 1) * depthChunk, croppeds[c]);
}
}
struct LightView {
uint8_t cams;
uint8_t projs;
mat4 c[6];
mat4 p[3];
};
static size_t compute_light_views(struct LightView lv[]) {
size_t totalTilesUsed = 0;
size_t s = 0;
for(int i = 0; i < LightCount; i++) {
isCube[s] = 0;
struct k3Light *l = &Lights[i];
/*if(!l->castShadow) {
continue;
}*/
if(l->type == k3_DIRECTIONAL) {
size_t CASCADE_COUNT = l->dir.cascadeCount;
glm_ortho(-60, 60, -60, 60, -60, 60, projs[s]);
lv[i].projs = CASCADE_COUNT;
lv[i].cams = CASCADE_COUNT;
mat4 croppeds[CASCADE_COUNT];
split_frustum(ProjMat, CASCADE_COUNT, croppeds);
for(int cascade = 0; cascade < CASCADE_COUNT; cascade++) {
mat4 invmainproj;
glm_mat4_inv_fast(croppeds[cascade], invmainproj);
glm_mat4_inv_fast(ProjMat, invmainproj);
mat4 frustummat;
glm_mat4_mul(CamMat, invmainproj, frustummat);
@ -1738,59 +1694,45 @@ static size_t compute_light_views(struct LightView lv[]) {
vec4 viewcenter;
glm_frustum_center(corners, viewcenter);
mat4 lightview;
glm_look_anyup(viewcenter, l->dir.direction, lightview);
mat4 view;
glm_look_anyup(viewcenter, l->dir.direction, view);
vec4 minaabb = {+HUGE_VALF, +HUGE_VALF, +HUGE_VALF};
vec4 maxaabb = {-HUGE_VALF, -HUGE_VALF, -HUGE_VALF};
glm_mat4_inv_fast(view, cams[s]);
for(int c = 0; c < 8; c++) {
vec4 lightspaceCorner;
glm_mat4_mulv(lightview, corners[c], lightspaceCorner);
glm_vec4_minv(minaabb, lightspaceCorner, minaabb);
glm_vec4_maxv(maxaabb, lightspaceCorner, maxaabb);
}
glm_ortho(minaabb[0], maxaabb[0], minaabb[1], maxaabb[1], minaabb[2] - 50, maxaabb[2], lv[i].p[cascade]);
glm_mat4_inv_fast(lightview, lv[i].c[cascade]);
}
s++;
} else if(l->type == k3_SPOT || l->type == k3_HALF_OMNI) {
lv[i].projs = 1;
lv[i].cams = 1;
glm_perspective(l->spot.angle, 1, 0.1, l->radius, lv[i].p[0]);
glm_perspective(l->spot.angle, 1, 0.1, l->radius, projs[s]);
mat4 view;
glm_look_anyup(l->spot.position, l->spot.direction, view);
glm_mat4_inv_fast(view, lv[i].c[0]);
glm_mat4_inv_fast(view, cams[s]);
s++;
} else if(l->type == k3_OMNI) {
static const vec3 dirs[] = {{0, 0, -1}, {0, 0, 1}, {-1, 0, 0}, {1, 0, 0}, {0, -1, 0}, {0, 1, 0}};
static const vec3 ups[] = {{0, 1, 0}, {0, 1, 0}, {0, 1, 0}, {0, 1, 0}, {0, 0, 1}, {0, 0, -1}};
lv[i].projs = 1;
lv[i].cams = 6;
mat4 proj;
glm_perspective(glm_rad(120), 1, 0.1, l->radius, proj);
glm_mat4_copy(proj, lv[i].p[0]);
for(int d = 0; d < 6; d++) {
glm_perspective(glm_rad(120), 1, 0.1, l->radius, projs[s]);
mat4 view;
glm_look(l->omni.position, dirs[d], ups[d], view);
glm_mat4_inv_fast(view, lv[i].c[d]);
glm_mat4_inv_fast(view, cams[s]);
isCube[s] = d != 0;
s++;
}
}
}
totalTilesUsed += lv[i].cams;
}
*_projs = projs;
*_cams = cams;
*_isCube = isCube;
return totalTilesUsed;
return s;
}
#ifdef k3_IRREGULAR_SHADOWS
@ -1912,7 +1854,9 @@ static void pass_irregular(int passnum, mat4 mainproj, mat4 maincam, mat4 lightp
enable_glsl_bones(glsl, mdl, bones);
}
if(k3IsSoftSkinning) {
enable_vertex_buffers(mdl, glsl);
if(k3CPUSkinning) {
apply_cpu_skinning(mdl, bones);
}
@ -1954,7 +1898,7 @@ void k3PassIrregular(struct k3Offscreen *mainview, mat4 mainproj, mat4 maincam)
mat4 *cams;
char *isCube;
count = compute_light_views(&projs, &cams, &isCube);
size_t count = compute_light_views(&projs, &cams, &isCube);
LightShadowsCount = count;
if(LightShadowsCount > LightShadowsCapacity) {
@ -2057,8 +2001,11 @@ void k3PassShadowmap(mat4 projection, mat4 cam, struct k3Offscreen *offscr) {
glm_mat4_copy(projection, ProjMat);
glm_mat4_copy(cam, CamMat);
struct LightView *views = alloca(sizeof(*views) * LightCount);
size_t totalTilesUsed = compute_light_views(views);
mat4 *projs;
mat4 *cams;
char *isCube;
size_t count = compute_light_views(&projs, &cams, &isCube);
ShadowAtlas = offscr;
@ -2073,7 +2020,7 @@ void k3PassShadowmap(mat4 projection, mat4 cam, struct k3Offscreen *offscr) {
LightShadowsCapacity = LightShadowsCount;
}
if(totalTilesUsed == 0) {
if(count == 0) {
return;
}
@ -2084,56 +2031,45 @@ void k3PassShadowmap(mat4 projection, mat4 cam, struct k3Offscreen *offscr) {
int cellsPerDimension = 0;
if(totalTilesUsed == 1) {
if(count == 1) {
cellsPerDimension = 1;
} else {
int cellsTotalSqrt = 1;
while((cellsTotalSqrt * cellsTotalSqrt) < totalTilesUsed) {
cellsTotalSqrt++;
int cellsTotalLog = 1;
while((1 << cellsTotalLog) < count) {
cellsTotalLog++;
}
cellsPerDimension = cellsTotalSqrt;
cellsPerDimension = 1 << ((cellsTotalLog + 1) / 2);
}
uint16_t sz = k3TexSzX(offscr->depth);
float cellSz = (float) sz / cellsPerDimension;
uint16_t cellSz = sz / cellsPerDimension;
size_t s = 0;
k3BeginOffscreen(offscr);
size_t i = 0;
for(size_t li = 0; li < LightCount; li++) {
struct LightView *lv = &views[li];
for(int camIdx = 0; camIdx < lv->cams; camIdx++) {
for(size_t i = 0; i < count; i++) {
int cellX = i % cellsPerDimension;
int cellY = i / cellsPerDimension;
int vp[] = {
(int) roundf(cellX * cellSz),
(int) roundf(cellY * cellSz),
(int) cellSz,
(int) cellSz
};
int vp[] = {cellX * cellSz, cellY * cellSz, cellSz, cellSz};
mat4 view = GLM_MAT4_IDENTITY_INIT;
glm_mat4_inv(lv->c[camIdx], view);
glm_mat4_inv(cams[i], view);
mat4 proj = GLM_MAT4_IDENTITY_INIT;
glm_mat4_copy(lv->projs == 1 ? lv->p[0] : lv->p[camIdx], proj);
LightShadows[li].vpCount = lv->projs;
if(lv->projs > 1 || camIdx == 0) {
glm_mat4_mul(proj, view, LightShadows[li].vp[camIdx]);
}
if(camIdx == 0) {
glm_vec4_copy((vec4) {i, (float) cellSz / sz, 0, 0}, LightShadows[li].atlasSegment);
if(!isCube[i]) {
glm_mat4_mul(projs[i], view, LightShadows[s].vp);
glm_vec4_copy((vec4) {i, (float) cellSz / sz, 0, 0}, LightShadows[s].atlasSegment);
s++;
}
glViewport(vp[0], vp[1], vp[2], vp[3]);
k3PassDepthOnly(proj, lv->c[camIdx], i == 0, false);
i++;
}
k3PassDepthOnly(projs[i], cams[i], i == 0, false);
}
k3EndOffscreen(offscr);
_mm_free(projs);
_mm_free(cams);
_mm_free(isCube);
}
void k3BatchClear() {
@ -2294,50 +2230,6 @@ void GlCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei
}
}
#include"compr/bc7enc.h"
static void *compress_rgba_bc7(const void *pixels, uint16_t width, uint16_t height, GLenum externalFmt, GLenum intype, size_t *compressedSize) {
static bool called = false;
if(!called) {
bc7enc_compress_block_init();
called = true;
}
assert(externalFmt == GL_RGBA);
assert(intype == GL_UNSIGNED_BYTE);
uint16_t blockWidth = (width + 3) / 4;
uint16_t blockHeight = (height + 3) / 4;
size_t blocks = blockWidth * blockHeight;
*compressedSize = blocks * 16;
uint8_t *output = calloc(blocks, 16);
#pragma omp parallel
{
bc7enc_compress_block_params p;
bc7enc_compress_block_params_init(&p);
#pragma omp for
for(size_t blk = 0; blk < blocks; blk++) {
uint8_t blockPixels[64];
uint16_t blkX = blk % blockWidth;
uint16_t blkY = blk / blockWidth;
memcpy(blockPixels + 0, pixels + 4 * (((blkY * 4) + 0) * width + (blkX * 4)), 16);
memcpy(blockPixels +16, pixels + 4 * (((blkY * 4) + 1) * width + (blkX * 4)), 16);
memcpy(blockPixels +32, pixels + 4 * (((blkY * 4) + 2) * width + (blkX * 4)), 16);
memcpy(blockPixels +48, pixels + 4 * (((blkY * 4) + 3) * width + (blkX * 4)), 16);
bc7enc_compress_block(output + blk * 16, blockPixels, &p);
}
}
return output;
}
void k3Init() {
if(GLAD_GL_ARB_debug_output) {
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
@ -2396,23 +2288,6 @@ void k3Init() {
"}\n"
, NULL), NULL);
}
/*if(GLAD_GL_KHR_texture_compression_astc_ldr) {
TextureCompressionEnabled = true;
} else */ if(GLAD_GL_ARB_texture_compression_bptc || GLAD_GL_VERSION_4_2) {
TextureCompressionEnabled = true;
TextureCompressionSRGBA = GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM;
TextureCompressionRGBA = GL_COMPRESSED_RGBA_BPTC_UNORM;
TextureOfflineCompressor = compress_rgba_bc7;
} else if(GL_EXT_texture_compression_s3tc) {
TextureCompressionEnabled = true;
TextureCompressionSRGBA = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT;
TextureCompressionRGBA = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
}
}
static size_t preprocess(char *src, const char*(*ldr)(const char *fn), const char ***strs, GLuint **sizes) {
@ -2749,29 +2624,14 @@ struct k3ARBFP *k3ProgramARBFP(const char *src) {
return (struct k3ARBFP*) (uintptr_t) p;
}
struct k3Offscreen *k3OffscreenCreateMultisampled(struct k3Tex *diffuse, struct k3Tex *depth, uint8_t samples) {
struct k3Offscreen *k3OffscreenCreate(struct k3Tex *diffuse, struct k3Tex *depth) {
k3Log(k3_INFO, "Init %sFBO", !diffuse && depth ? "depth-only " : "");
if(samples && (!GLAD_GL_EXT_framebuffer_multisample || !GLAD_GL_EXT_framebuffer_blit)) {
samples = 0;
k3Log(k3_WARN, "Multisampled offscreens not supported.");
}
if(!GLAD_GL_EXT_framebuffer_object) {
k3Log(k3_ERR, "Non-FBO offscreens not implemented");
return NULL;
}
GLuint fbo = 0;
if(GLAD_GL_EXT_framebuffer_object) {
glGenFramebuffersEXT(1, &fbo);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
struct k3Offscreen *ret = calloc(1, sizeof(*ret));
ret->fbo = fbo;
ret->diffuse = diffuse;
ret->depth = depth;
ret->multisampling.samples = samples;
if(diffuse) {
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, GL_FROM_K3TEX(diffuse), 0);
} else {
@ -2787,43 +2647,23 @@ struct k3Offscreen *k3OffscreenCreateMultisampled(struct k3Tex *diffuse, struct
k3Log(k3_WARN, "Framebuffer incomplete");
}
if(samples) {
GLuint msfbo;
glGenFramebuffersEXT(1, &msfbo);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, msfbo);
ret->multisampling.fbo = msfbo;
if(diffuse) {
glGenRenderbuffersEXT(1, &ret->multisampling.rboDiffuse);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, ret->multisampling.rboDiffuse);
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples, diffuse->glInternalFormat, diffuse->szX, diffuse->szY);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, ret->multisampling.rboDiffuse);
}
if(depth) {
glGenRenderbuffersEXT(1, &ret->multisampling.rboDepth);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, ret->multisampling.rboDepth);
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples, depth->glInternalFormat, depth->szX, depth->szY);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, ret->multisampling.rboDepth);
}
}
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
glDrawBuffer(GL_BACK); // XXX: this should not be necessary
return ret;
} else {
k3Log(k3_ERR, "Non-FBO offscreens not implemented");
return NULL;
}
struct k3Offscreen *k3OffscreenCreate(struct k3Tex *diffuse, struct k3Tex *depth) {
return k3OffscreenCreateMultisampled(diffuse, depth, 0);
struct k3Offscreen *ret = malloc(sizeof(*ret));
ret->fbo = fbo;
ret->diffuse = diffuse;
ret->depth = depth;
return ret;
}
void k3BeginOffscreen(struct k3Offscreen *offscr) {
if(GLAD_GL_EXT_framebuffer_object) {
GLuint fbo = offscr->multisampling.samples > 0 ? offscr->multisampling.fbo : offscr->fbo;
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, offscr->fbo);
struct k3Tex *t = offscr->diffuse ? offscr->diffuse : offscr->depth;
glViewport(0, 0, k3TexSzX(t), k3TexSzY(t));
@ -2834,12 +2674,6 @@ void k3BeginOffscreen(struct k3Offscreen *offscr) {
void k3EndOffscreen(struct k3Offscreen *offscr) {
if(GLAD_GL_EXT_framebuffer_object) {
if(offscr->multisampling.samples) {
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, offscr->fbo);
glBlitFramebufferEXT(0, 0, offscr->diffuse->szX, offscr->diffuse->szY, 0, 0, offscr->diffuse->szX, offscr->diffuse->szY, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST);
}
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
glViewport(0, 0, MainWidth, MainHeight);
} else {
@ -2855,9 +2689,7 @@ void k3BlitToScreenEffect(struct k3Offscreen *offscr, int additive, int effect,
if(GLAD_GL_EXT_framebuffer_object) {
glActiveTexture(GL_TEXTURE0);
struct k3Tex *tex = offscr->diffuse ? offscr->diffuse : offscr->depth;
glBindTexture(GL_TEXTURE_2D, GL_FROM_K3TEX(tex));
glBindTexture(GL_TEXTURE_2D, GL_FROM_K3TEX(offscr->diffuse));
if(additive) {
glEnable(GL_BLEND);
@ -2904,7 +2736,7 @@ void k3BlitToScreenEffect(struct k3Offscreen *offscr, int additive, int effect,
}
GLint uSz = glGetUniformLocation(GL_FROM_K3GLSL(basicBlitProgram), "u_sz");
glUniform2f(uSz, k3TexSzX(tex), k3TexSzY(tex));
glUniform2f(uSz, k3TexSzX(offscr->diffuse), k3TexSzY(offscr->diffuse));
glDrawArrays(GL_TRIANGLES, 0, 3);
} else {
@ -2912,8 +2744,8 @@ void k3BlitToScreenEffect(struct k3Offscreen *offscr, int additive, int effect,
glUseProgramObjectARB(effect == k3_GLSL ? GL_FROM_K3GLSL(program) : 0);
}
float bleedW = 1.0f / k3TexSzX(tex);
float bleedH = 1.0f / k3TexSzY(tex);
float bleedW = 1.0f / k3TexSzX(offscr->diffuse);
float bleedH = 1.0f / k3TexSzY(offscr->diffuse);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

View File

@ -6,13 +6,8 @@
#include<cglm/mat4.h>
#include<cglm/quat.h>
#ifdef k3_MULTITHREAD
#include<pthread.h>
#endif
void k3Init();
void k3Resize(uint16_t width, uint16_t height);
void k3Update();
enum k3TexType {
k3_DIFFUSE, k3_NORMAL, k3_DISPLACEMENT, k3_EMISSION, k3_ROUGHNESS, k3_ALPHA,
@ -48,8 +43,7 @@ struct k3ARBFP;
struct k3ARBFP *k3ProgramARBFP(const char *src);
extern uint8_t k3GraphicalReduction;
extern bool k3IsCore;
extern bool k3IsSoftSkinning;
extern int k3IsCore;
struct k3Mat {
struct {
@ -97,7 +91,6 @@ struct k3Mat {
char transparent;
char nocull;
char alphatest;
char depthwrite;
} passes[1];
};
@ -141,7 +134,6 @@ struct k3Light {
_Alignas(16) union {
struct {
vec4 direction;
uint8_t cascadeCount;
} dir;
struct {
vec4 position;
@ -163,8 +155,6 @@ struct k3Storage;
void k3StorageRef(struct k3Storage*);
void k3StorageUnref(struct k3Storage*);
#define k3_ATTRIB_NONE (NULL)
#define k3_ATTRIB_EMPTY ((void*) 1)
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);
@ -195,7 +185,6 @@ void k3PassDepthOnly(mat4 projection, mat4 cam, int clear, int cull);
void k3PassShadowmap(mat4 projection, mat4 cam, struct k3Offscreen *offscr);
struct k3Offscreen;
struct k3Offscreen *k3OffscreenCreateMultisampled(struct k3Tex *diffuse, struct k3Tex *depth, uint8_t samples);
struct k3Offscreen *k3OffscreenCreate(struct k3Tex *diffuse, struct k3Tex *depth);
void k3BeginOffscreen(struct k3Offscreen*);
void k3EndOffscreen(struct k3Offscreen*);

View File

@ -1,83 +0,0 @@
#pragma once
#include"k3.h"
#include"gl.h"
#include<cglm/vec2.h>
#include<cglm/frustum.h>
#include<cglm/cam.h>
#define GL_FROM_K3TEX(k3t) ((k3t) ? (k3t)->tex : 0)
#define GL_FROM_K3MARCHER(k3m) ((GLuint) (uintptr_t) (k3m))
#define GL_FROM_K3ARBVP(k3m) ((GLuint) (uintptr_t) (k3m))
#define GL_FROM_K3ARBFP(k3m) ((GLuint) (uintptr_t) (k3m))
#define GL_FROM_K3GLSL(k3m) ((GLuint) (uintptr_t) (k3m))
struct k3Tex {
GLuint tex;
int cubemap;
uint32_t szX;
uint32_t szY;
uint32_t szZ;
GLuint glInternalFormat;
GLuint glExternalFormat;
GLuint glInType;
bool mipmap;
// Asynchronous decoding
uint8_t deferredRemaining;
uint8_t *deferredData[6];
struct k3Tex *deferredNext;
};
struct k3Storage {
int16_t ref;
void(*free)(struct k3Storage*);
};
struct k3StorageBasic {
struct k3Storage;
GLuint gl;
};
struct k3Offscreen {
GLuint fbo;
struct k3Tex *diffuse;
struct k3Tex *depth;
struct {
uint8_t samples;
GLuint fbo;
GLuint rboDiffuse;
GLuint rboDepth;
} multisampling;
};
struct k3Mdl {
struct {
vec3 *pos;
uint8_t *boneids;
uint16_t *boneweights;
} cpuSkinning;
size_t verts;
struct k3StorageBasic *vstore;
struct k3StorageBasic *estore;
uint16_t meshCount;
struct k3Mesh *meshes;
size_t boneCount;
mat4 *invBind;
uint8_t *boneParents;
uint16_t animCount;
struct k3Animation **anims;
vec3 aabb[2];
int offV, offN, offC, offU, offB, offT;
const char *debugname;
};

View File

@ -12,8 +12,6 @@ struct S {
};
static struct k3Tex *activeTex;
static float activeBorderRadius;
static size_t SCount, SCapacity;
static struct S *S;
@ -27,33 +25,21 @@ void k3BatchInit() {
"in vec2 a_pos;\n"
"in vec2 a_uv;\n"
"in vec4 a_color;\n"
"in vec2 a_size;\n"
"out vec2 v_uv;\n"
"out vec4 v_color;\n"
"out vec2 v_size;\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"
"}\n"
, NULL), k3ShaderGLSLF(
"#version 330\n"
"uniform sampler2D u_tex;\n"
"uniform float u_texuse;\n"
"uniform float u_borderradius;\n"
"in vec2 v_uv;\n"
"in vec4 v_color;\n"
"in vec2 v_size;\n"
"out vec4 fragcolor;\n"
"void main() {\n"
" vec2 sz = v_size / 2.0;\n"
" vec2 c = abs(v_uv * 2.0 - 1.0);\n"
" c = c * (sz + u_borderradius);\n"
" c = max(c - sz, 0.0);\n"
" if(length(c) > u_borderradius) {\n"
" discard;\n"
" }\n"
" fragcolor = mix(vec4(1, 1, 1, 1), texture2D(u_tex, v_uv), u_texuse) * v_color;\n"
"}\n"
, NULL), NULL);
@ -62,11 +48,10 @@ void k3BatchInit() {
}
}
void k3BatchAdd(struct k3Tex *tex, struct k3RectF src, struct k3RectF dst, float rot, vec4 color, float borderRadius) {
if(activeTex != tex || borderRadius != activeBorderRadius) {
void k3BatchAdd(struct k3Tex *tex, struct k3RectF src, struct k3RectF dst, float rot, vec4 color) {
if(activeTex != tex) {
k3BatchFlush();
activeTex = tex;
activeBorderRadius = borderRadius;
}
if(SCount == SCapacity) {
@ -88,8 +73,6 @@ void k3BatchAdd(struct k3Tex *tex, struct k3RectF src, struct k3RectF dst, float
}
void k3BatchFlush() {
if(!S) return;
if(!k3IsCore) {
glDisable(GL_NORMALIZE);
@ -125,107 +108,89 @@ void k3BatchFlush() {
if(k3IsCore) {
glUseProgram((GLuint) coreProg);
float *farr = alloca(SCount * 60 * sizeof(*farr));
float *farr = alloca(SCount * 48 * sizeof(*farr));
struct S *s = S;
for(size_t i = 0; i < SCount; i++) {
farr[i * 60 + 0] = s->dst.x;
farr[i * 60 + 1] = s->dst.y;
farr[i * 60 + 2] = s->src.x;
farr[i * 60 + 3] = s->src.y + s->src.h;
farr[i * 60 + 4] = s->color[0];
farr[i * 60 + 5] = s->color[1];
farr[i * 60 + 6] = s->color[2];
farr[i * 60 + 7] = s->color[3];
farr[i * 60 + 8] = s->dst.w;
farr[i * 60 + 9] = s->dst.h;
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 * 60 + 10] = s->dst.x + s->dst.w;
farr[i * 60 + 11] = s->dst.y;
farr[i * 60 + 12] = s->src.x + s->src.w;
farr[i * 60 + 13] = s->src.y + s->src.h;
farr[i * 60 + 14] = s->color[0];
farr[i * 60 + 15] = s->color[1];
farr[i * 60 + 16] = s->color[2];
farr[i * 60 + 17] = s->color[3];
farr[i * 60 + 18] = s->dst.w;
farr[i * 60 + 19] = s->dst.h;
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 * 60 + 20] = s->dst.x + s->dst.w;
farr[i * 60 + 21] = s->dst.y + s->dst.h;
farr[i * 60 + 22] = s->src.x + s->src.w;
farr[i * 60 + 23] = s->src.y;
farr[i * 60 + 24] = s->color[0];
farr[i * 60 + 25] = s->color[1];
farr[i * 60 + 26] = s->color[2];
farr[i * 60 + 27] = s->color[3];
farr[i * 60 + 28] = s->dst.w;
farr[i * 60 + 29] = s->dst.h;
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 * 60 + 30] = s->dst.x;
farr[i * 60 + 31] = s->dst.y;
farr[i * 60 + 32] = s->src.x;
farr[i * 60 + 33] = s->src.y + s->src.h;
farr[i * 60 + 34] = s->color[0];
farr[i * 60 + 35] = s->color[1];
farr[i * 60 + 36] = s->color[2];
farr[i * 60 + 37] = s->color[3];
farr[i * 60 + 38] = s->dst.w;
farr[i * 60 + 39] = s->dst.h;
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 * 60 + 40] = s->dst.x + s->dst.w;
farr[i * 60 + 41] = s->dst.y + s->dst.h;
farr[i * 60 + 42] = s->src.x + s->src.w;
farr[i * 60 + 43] = s->src.y;
farr[i * 60 + 44] = s->color[0];
farr[i * 60 + 45] = s->color[1];
farr[i * 60 + 46] = s->color[2];
farr[i * 60 + 47] = s->color[3];
farr[i * 60 + 48] = s->dst.w;
farr[i * 60 + 49] = s->dst.h;
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 * 60 + 50] = s->dst.x;
farr[i * 60 + 51] = s->dst.y + s->dst.h;
farr[i * 60 + 52] = s->src.x;
farr[i * 60 + 53] = s->src.y;
farr[i * 60 + 54] = s->color[0];
farr[i * 60 + 55] = s->color[1];
farr[i * 60 + 56] = s->color[2];
farr[i * 60 + 57] = s->color[3];
farr[i * 60 + 58] = s->dst.w;
farr[i * 60 + 59] = s->dst.h;
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 * 60 * sizeof(*farr), farr, GL_DYNAMIC_DRAW);
glBufferDataARB(GL_ARRAY_BUFFER_ARB, SCount * 48 * sizeof(*farr), farr, GL_DYNAMIC_DRAW);
glUniform1f(glGetUniformLocation((GLuint) coreProg, "u_texuse"), !!activeTex);
glUniform1f(glGetUniformLocation((GLuint) coreProg, "u_borderradius"), activeBorderRadius);
GLint aPos = glGetAttribLocation((GLuint) coreProg, "a_pos");
GLint aUv = glGetAttribLocation((GLuint) coreProg, "a_uv");
GLint aColor = glGetAttribLocation((GLuint) coreProg, "a_color");
GLint aSize = glGetAttribLocation((GLuint) coreProg, "a_size");
glEnableVertexAttribArray(aPos);
glEnableVertexAttribArray(aUv);
glEnableVertexAttribArray(aColor);
glEnableVertexAttribArray(aSize);
glVertexAttribPointer(aPos, 2, GL_FLOAT, GL_FALSE, 40, (void*) 0);
glVertexAttribPointer(aUv, 2, GL_FLOAT, GL_FALSE, 40, (void*) 8);
glVertexAttribPointer(aColor, 4, GL_FLOAT, GL_FALSE, 40, (void*) 16);
glVertexAttribPointer(aSize, 2, GL_FLOAT, GL_FALSE, 40, (void*) 32);
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);
glDisableVertexAttribArray(aSize);
} else {
if(GLAD_GL_ARB_shading_language_100) {
glUseProgramObjectARB(0);

View File

@ -10,5 +10,5 @@ struct k3RectF {
float h;
};
void k3BatchAdd(struct k3Tex *tex, struct k3RectF src, struct k3RectF dst, float rot, vec4 color, float borderRadius);
void k3BatchAdd(struct k3Tex *tex, struct k3RectF src, struct k3RectF dst, float rot, vec4 color);
void k3BatchFlush();

View File

@ -32,8 +32,8 @@ int make_mb1() {
if(!v) return 0;
struct k3GLSLF *f = !k3IsCore ? k3ShaderGLSLF(
"#define THRESHOLD 0.6" "\n"
"#define FACTOR 0.07" "\n"
"#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"
@ -57,8 +57,8 @@ int make_mb1() {
"}" "\n"
, NULL) : k3ShaderGLSLF(
"#version 330\n"
"#define THRESHOLD 0.6" "\n"
"#define FACTOR 0.07" "\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"
@ -122,15 +122,15 @@ int make_mb2() {
"}" "\n"
"void main() {" "\n"
" vec3 c = vec3(0);" "\n"
" c += 0.0020 * get_col(v_uv + vec2(0, -4.0 / 256.0));" "\n"
" c += 0.0060 * get_col(v_uv + vec2(0, -3.0 / 256.0));" "\n"
" c += 0.0606 * get_col(v_uv + vec2(0, -2.0 / 256.0));" "\n"
" c += 0.2417 * get_col(v_uv + vec2(0, -1.0 / 256.0));" "\n"
" c += 0.3829 * get_col(v_uv + vec2(0, +0.0 / 256.0));" "\n"
" c += 0.2417 * get_col(v_uv + vec2(0, +1.0 / 256.0));" "\n"
" c += 0.0606 * get_col(v_uv + vec2(0, +2.0 / 256.0));" "\n"
" c += 0.0060 * get_col(v_uv + vec2(0, +3.0 / 256.0));" "\n"
" c += 0.0020 * get_col(v_uv + vec2(0, +4.0 / 256.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(
@ -144,15 +144,15 @@ int make_mb2() {
"}" "\n"
"void main() {" "\n"
" vec3 c = vec3(0);" "\n"
" c += 0.0020 * get_col(v_uv + vec2(0, -4.0 / 256.0));" "\n"
" c += 0.0060 * get_col(v_uv + vec2(0, -3.0 / 256.0));" "\n"
" c += 0.0606 * get_col(v_uv + vec2(0, -2.0 / 256.0));" "\n"
" c += 0.2417 * get_col(v_uv + vec2(0, -1.0 / 256.0));" "\n"
" c += 0.3829 * get_col(v_uv + vec2(0, +0.0 / 256.0));" "\n"
" c += 0.2417 * get_col(v_uv + vec2(0, +1.0 / 256.0));" "\n"
" c += 0.0606 * get_col(v_uv + vec2(0, +2.0 / 256.0));" "\n"
" c += 0.0060 * get_col(v_uv + vec2(0, +3.0 / 256.0));" "\n"
" c += 0.0020 * get_col(v_uv + vec2(0, +4.0 / 256.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);
@ -237,7 +237,7 @@ int make_tonemapper() {
"}" "\n"
"vec3 get_col(vec2 uv) {" "\n"
" vec3 col = texture2D(u_tex, uv).rgb;" "\n"
" col = toner(col, 0.80, 1.0);" "\n"
" col = toner(col, 0.80, 1.5);" "\n"
" return col;" "\n"
"}" "\n"
"void main() {" "\n"

View File

@ -131,7 +131,6 @@ void k3FontDraw(struct k3Font *this, float xStart, float yStart, float sz, const
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) {
@ -139,7 +138,7 @@ void k3FontDraw(struct k3Font *this, float xStart, float yStart, float sz, const
y + ((-g->height - g->yoffset) * this->lineScale + 1) * sz,
g->width * this->lineScale * sz,
g->height * this->lineScale * sz
}, 0, color, 0);
}, 0, color);
x += g->xadvance * this->lineScale * sz;
}

View File

@ -70,30 +70,9 @@ bool k3MEventSend(struct k3MEvent *ev) {
return true;
}
static void obj_draw(struct k3MObj *this) {
struct k3MProperty *borderRadiusProp = k3MFindProperty(this, k3M_PROP_BORDER_RADIUS, false);
float borderRadius = borderRadiusProp ? borderRadiusProp->si[0] : 0;
struct k3MProperty *bgColorProp = k3MFindProperty(this, k3M_PROP_BG_COLOR, false);
vec4 bgColor = {0, 0, 0, 0};
if(bgColorProp) {
bgColor[0] = bgColorProp->si[0] / 255.0;
bgColor[1] = bgColorProp->si[1] / 255.0;
bgColor[2] = bgColorProp->si[2] / 255.0;
bgColor[3] = bgColorProp->si[3] / 255.0;
}
k3BatchAdd(NULL, (struct k3RectF) {0, 0, 1, 1}, (struct k3RectF) {
this->x, this->y,
this->w, this->h
}, 0, bgColor, borderRadius);
}
static bool label_draw(struct k3MEvent *ev, uint8_t *ud) {
struct k3MLabel *this = (void*) ev->target;
obj_draw((void*) this);
if(this->txt) {
k3FontDraw(this->font, this->x, this->y, this->sz, this->txt, (vec4) {1, 1, 1, 1});
}
@ -139,28 +118,50 @@ void k3MAddChild(struct k3MObj *parent, struct k3MObj *child) {
child->parent = parent;
}
void k3MOverrideProperty(struct k3MObj *obj, struct k3MProperty n) {
struct k3MProperty *o = k3MFindProperty(obj, n.type, true);
/*static struct k3Menu *k3ScreenFuncMouse(struct k3Menu *_, int16_t x, int16_t y, int ev) {
struct k3Screen *this = (void*) _;
if(!o) {
obj->properties = realloc(obj->properties, ++obj->propertyCount * sizeof(*obj->properties));
o = &obj->properties[obj->propertyCount - 1];
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);
}
memcpy(o, &n, sizeof(n));
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;
}
struct k3MProperty *k3MFindProperty(struct k3MObj *obj, enum k3MPropertyType t, bool direct) {
for(size_t i = 0; i < obj->propertyCount; i++) {
if(obj->properties[i].type == t) {
return &obj->properties[i];
}
}
if(direct || !obj->parent) {
return NULL;
}
return k3MFindProperty(obj->parent, t, direct);
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;
@ -193,12 +194,6 @@ static bool screen_ev(struct k3MEvent *ev, uint8_t *ud) {
}
if(innermost != this->lastHover) {
this->lastHover->hovered = false;
innermost->hovered = true;
this->lastHover = innermost;
}
if(innermost != (void*) this) {
if(ev->code == k3M_EVENT_MOUSE_PRESS) {
@ -247,8 +242,6 @@ static bool screen_ev(struct k3MEvent *ev, uint8_t *ud) {
struct k3MScreen *k3MScreen() {
struct k3MScreen *ret = calloc(1, sizeof(*ret));
ret->lastHover = (void*) ret;
k3MRegisterEventHandler(ret, k3M_EVENT_ALL, screen_ev, NULL, 0);
return ret;
@ -257,9 +250,12 @@ struct k3MScreen *k3MScreen() {
static bool textbutton_draw(struct k3MEvent *ev, uint8_t *ud) {
struct k3MTextButton *this = (void*) ev->target;
obj_draw((void*) this);
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);
@ -284,9 +280,12 @@ 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);
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;

View File

@ -61,19 +61,6 @@ typedef struct k3MEventHandler {
uint16_t code;
} k3MEventHandler;
enum k3MPropertyType {
k3M_PROP_BG_COLOR,
k3M_PROP_BORDER_RADIUS,
};
struct k3MProperty {
enum k3MPropertyType type;
union {
intmax_t si[4];
void *ptr;
uint8_t buf[32];
};
};
struct k3MObj {
struct k3MObj *parent;
@ -89,9 +76,6 @@ struct k3MObj {
k3MEventHandler *handlers;
size_t handlerCount;
struct k3MProperty *properties;
size_t propertyCount;
};
#define k3MenuSetBounds(a, x, y, w, h) k3MenuSetBounds_((struct k3MObj*) (a), (x), (y), (w), (h))
@ -105,9 +89,6 @@ bool k3MEventSend(struct k3MEvent *ev);
int k3MRemoveChild(struct k3MObj *parent, struct k3MObj *child);
void k3MAddChild(struct k3MObj *parent, struct k3MObj *child);
void k3MOverrideProperty(struct k3MObj *obj, struct k3MProperty);
struct k3MProperty *k3MFindProperty(struct k3MObj *obj, enum k3MPropertyType, bool direct);
struct k3MLabel {
struct k3MObj;
@ -121,7 +102,6 @@ struct k3MScreen {
struct k3MObj;
struct k3MObj *keyboardFocus;
struct k3MObj *lastHover;
};
struct k3MScreen *k3MScreen();

View File

@ -1,185 +0,0 @@
#include"k3particles.h"
#include"k3_internal.h"
struct xorshift128_state {
uint32_t x[4];
};
uint32_t xorshift128(struct xorshift128_state *state) {
uint32_t t = state->x[3];
uint32_t s = state->x[0];
state->x[3] = state->x[2];
state->x[2] = state->x[1];
state->x[1] = s;
t ^= t << 11;
t ^= t >> 8;
return state->x[0] = t ^ s ^ (s >> 19);
}
struct xorshift128_state xs = {{1, 2, 3, 4}};
static uint32_t randint(uint32_t min, uint32_t max) {
uint32_t x;
do {
x = xorshift128(&xs);
} while(0x100000000UL - 0x100000000UL % ((uint64_t) max + 1) <= x);
return x / (0x100000000UL / ((uint64_t) max + 1));
}
static float randfloat() {
union { uint32_t u32; float f; } u = { .u32 = xorshift128(&xs) >> 9 | 0x3f800000 };
return u.f - 1.0;
}
void k3CPUQuadParticlesInit(struct k3CPUQuadParticles *this, struct k3Mat *mat) {
uint16_t *inds = calloc(sizeof(*inds), this->capacity * 6);
for(size_t i = 0; i < this->capacity; i++) {
inds[i * 6 + 0] = i * 4 + 0;
inds[i * 6 + 1] = i * 4 + 1;
inds[i * 6 + 2] = i * 4 + 2;
inds[i * 6 + 3] = i * 4 + 0;
inds[i * 6 + 4] = i * 4 + 2;
inds[i * 6 + 5] = i * 4 + 3;
}
this->mdl = k3MdlCreate(this->capacity * 4, this->capacity * 6, 0, k3_ATTRIB_EMPTY, k3_ATTRIB_EMPTY, k3_ATTRIB_EMPTY, k3_ATTRIB_EMPTY, NULL, NULL, inds, NULL, NULL);
k3MdlAddMesh(this->mdl, mat, 0, this->capacity * 6);
k3MdlSetDebugName(this->mdl, "k3CPUQuadParticles");
free(inds);
this->positions = calloc(sizeof(*this->positions), this->capacity);
this->velocities = calloc(sizeof(*this->velocities), this->capacity);
this->sizes = calloc(sizeof(*this->sizes), this->capacity);
this->lifetimes = calloc(sizeof(*this->lifetimes), this->capacity);
}
static void random_cone_vector(float coneAngle, vec3 output) {
float minZ = cosf(coneAngle);
float z = randfloat() * (1 - minZ) + minZ;
float phi = randfloat() * 6.2831853;
output[0] = sqrtf(1 - z * z) * cosf(phi);
output[1] = z;
output[2] = sqrtf(1 - z * z) * sinf(phi);
}
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 halfRight, halfUp;
glm_vec3_scale(cameraRight, 0.5, halfRight);
glm_vec3_scale(cameraUp, 0.5, halfUp);
#pragma omp parallel for
for(size_t i = 0; i < this->count; i++) {
glm_vec3_copy(this->positions[i], vpos[i * 4 + 0]);
glm_vec3_copy(this->positions[i], vpos[i * 4 + 1]);
glm_vec3_copy(this->positions[i], vpos[i * 4 + 2]);
glm_vec3_copy(this->positions[i], vpos[i * 4 + 3]);
glm_vec3_muladds(halfRight, -this->sizes[i], vpos[i * 4 + 0]);
glm_vec3_muladds(halfUp, -this->sizes[i], vpos[i * 4 + 0]);
glm_vec3_muladds(halfRight, this->sizes[i], vpos[i * 4 + 1]);
glm_vec3_muladds(halfUp, -this->sizes[i], vpos[i * 4 + 1]);
glm_vec3_muladds(halfRight, this->sizes[i], vpos[i * 4 + 2]);
glm_vec3_muladds(halfUp, this->sizes[i], vpos[i * 4 + 2]);
glm_vec3_muladds(halfRight, -this->sizes[i], vpos[i * 4 + 3]);
glm_vec3_muladds(halfUp, this->sizes[i], vpos[i * 4 + 3]);
vec4 color;
glm_vec4_lerp(this->colorEnd, this->colorStart, this->lifetimes[i] / this->particleLifetime, color);
for(size_t c = 0; c < 16; c += 4) {
vcols[i * 16 + c + 0] = color[0] * 255;
vcols[i * 16 + c + 1] = color[1] * 255;
vcols[i * 16 + c + 2] = color[2] * 255;
vcols[i * 16 + c + 3] = color[3] * 255;
}
glm_vec2_copy((vec2) {0, 0}, vuvs[i * 4 + 0]);
glm_vec2_copy((vec2) {1, 0}, vuvs[i * 4 + 1]);
glm_vec2_copy((vec2) {1, 1}, vuvs[i * 4 + 2]);
glm_vec2_copy((vec2) {0, 1}, vuvs[i * 4 + 3]);
for(size_t c = 0; c < 12; c += 3) {
vnrms[i * 12 + c + 0] = (uint8_t) (cameraFront[0] * 127);
vnrms[i * 12 + c + 1] = (uint8_t) (cameraFront[1] * 127);
vnrms[i * 12 + c + 2] = (uint8_t) (cameraFront[2] * 127);
}
}
// This update the AABB
k3MdlUpdatePos(this->mdl, vpos);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, this->mdl->vstore->gl);
//glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, this->mdl->offV, sizeof(*vpos) * this->capacity * 4, vpos);
glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, this->mdl->offC, sizeof(*vcols) * this->capacity * 4 * 4, vcols);
glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, this->mdl->offU, sizeof(*vuvs) * this->capacity * 4, vuvs);
glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, this->mdl->offN, sizeof(*vnrms) * this->capacity * 4 * 3, vnrms);
this->mdl->meshes[0].idxNumber = this->count * 6;
free(vpos);
free(vcols);
free(vuvs);
free(vnrms);
}
static void copy_particle(struct k3CPUQuadParticles *this, size_t from, size_t to) {
glm_vec3_copy(this->positions[from], this->positions[to]);
glm_vec3_copy(this->velocities[from], this->velocities[to]);
this->sizes[to] = this->sizes[from];
this->lifetimes[to] = this->lifetimes[from];
}
void k3CPUQuadParticlesUpdate(struct k3CPUQuadParticles *this, float dt, vec3 cameraRight, vec3 cameraUp, vec3 cameraFront) {
size_t numGenerated = dt * this->emissionRate;
if((this->emissionLifetime -= dt) <= 0) {
this->emissionEnabled = false;
}
if(!this->emissionEnabled) numGenerated = 0;
if(this->count + numGenerated > this->capacity) {
numGenerated = this->capacity - this->count;
}
for(size_t i = this->count, j = 0; j < numGenerated; i++, j++, this->count++) {
glm_vec3_copy(this->origin, this->positions[i]);
random_cone_vector(this->emissionConeAngle, this->velocities[i]);
glm_vec3_scale(this->velocities[i], 2, this->velocities[i]);
this->sizes[i] = 1;
this->lifetimes[i] = this->particleLifetime;
}
vec3 accdt;
glm_vec3_scale(this->gravity, dt, accdt);
for(size_t i = 0; i < this->count;) {
glm_vec3_add(this->velocities[i], accdt, this->velocities[i]);
vec3 veldt;
glm_vec3_scale(this->velocities[i], dt, veldt);
glm_vec3_add(this->positions[i], veldt, this->positions[i]);
this->lifetimes[i] -= dt;
if(this->lifetimes[i] <= 0) {
copy_particle(this, --this->count, i);
} else {
i++;
}
}
regenerate_model(this, cameraRight, cameraUp, cameraFront);
}

View File

@ -1,32 +0,0 @@
#pragma once
#include<cglm/vec3.h>
#include<stdbool.h>
#include"k3.h"
struct k3CPUQuadParticles {
size_t capacity;
size_t count;
vec3 *positions;
vec3 *velocities;
float *sizes;
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*);
void k3CPUQuadParticlesUpdate(struct k3CPUQuadParticles*, float dt, vec3 cameraRight, vec3 cameraUp, vec3 cameraFront);