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