Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /******************************************************************************/
- /******************************************************************************/
- //"opengl_metaballs_2025-06-26\src\user_audio.cpp":
- #include <public_stuff.hpp>
- //SoundEngine sfx;
- void user_audio(StereoF32* stream, u32 len, u32 sampleRate, f64 timeStamp)
- {
- // This plays a normal 440Hz sine wave (commented!)
- /*
- // The static keyword here just makes the variable persistent, in that
- // its state is preserved between each call to user_audio
- static u64 t = 0; // u[nsigned] 64-bit integer
- for(u32 i=0; i<len; ++i){ //For every sample to be filled in the audio buffer
- // t is incremented every sample, and is divided by the sample rate to
- // basically make a percentage of how far it is through a second.
- // This is then multiplied by 2pi, which effectively makes it oscillate
- // once every second if you fed cycle into sin directly
- f32 cycle = ((f32)(t++)/sampleRate) * M_2PIf;
- // cycle is multiplied by 440 so that it oscillates 440 times a second
- // instead of just once.
- // (Also, sinF is just sin but it uses 32-bit f[loats] instead of 64-bit,
- // and unlike the actual sinf, this is a custom implementation)
- f32 smp = sinF(cycle*440); // This ofc returns a number from -1.0 to 1.0
- // 20% volume
- smp *= 0.20f;
- // Since the audio stream is stereo, the sample is applied to
- // both 'ears' so-to-speak.
- stream[i].l = smp;
- stream[i].r = smp;
- }
- // Unnecessary, since a u64 is so big, but this makes it so that
- // even if it was a smaller integer size, it will never overflow.
- // (The % operator does a division, but gets the remainder instead)
- t %= sampleRate;
- */
- /*
- sfx.sampleRate = sample_rate;
- if(!sfx.mixTracks(stream, len, timeStamp)){
- _printf("ERROR: sfx.mixTracks failed!\n");
- }
- */
- }
- /******************************************************************************/
- /******************************************************************************/
- //"opengl_metaballs_2025-06-26\src\user_main.cpp":
- #include <win32/opengl.hpp>
- #include <public_stuff.hpp>
- char infoLogPostfix[512-64];
- char infoLogBuffer[512];
- #define MAX_SPHERE_COUNT 256*256
- #define MAX_METABALL_SPEED 5000.0f
- union r16 { u16 u; s16 s; };
- struct sphere {
- f32 x, y;
- r16 velX, velY; // Indexes into a lookup table of velocities
- f32 m;
- };
- /*
- //Returns the normal of the surface at the given position.
- vec3 Normal(vec3 pos)
- {
- vec3 offset = vec3(NORMAL_SMOOTHNESS, 0, 0);
- vec3 normal = vec3
- (
- Scene(pos - offset.xyz) - Scene(pos + offset.xyz),
- Scene(pos - offset.zxy) - Scene(pos + offset.zxy),
- Scene(pos - offset.yzx) - Scene(pos + offset.yzx)
- );
- return normalize(normal);
- }
- vec3 hsv2rgb(vec3 c)
- {
- vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
- vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
- return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
- }
- //Scene shading.
- //position, lightPos
- vec3 Shade(vec3 position, vec3 normal, vec3 rayOrigin,vec3 rayDirection,vec2 pixel)
- {
- float ang = iTime * 2.0;
- vec3 lightPos = vec3(cos(ang), cos(ang*2.0), sin(ang)) * 2.0;
- //float shade = (32.0-length(position-rayOrigin))/32.0;
- float shade = (32.0-length(position-lightPos))/32.0;
- shade = clamp(shade, 0.0, 1.0);
- // best seems to be (30/1024)*3
- float GAMMA = (iMouse.x/iResolution.x)*4.0;
- shade = pow(shade, 1.0/(GAMMA));
- //vec3 color = vec3(0);
- //float ang = iTime * 2.0;
- //vec3 lightPos = vec3(cos(ang), cos(ang*2.0), sin(ang)) * 2.0;
- //Normal shading
- //float shade = 0.4 * max(0.0, normal, normalize(-lightPos)));
- //Specular highlight
- //shade += 0.6 * max(0.0, dot(-reflect(normalize(position - lightPos), normal), rayDirection));
- //Linear falloff
- //shade *= (16.0-distance(position, lightPos))/16.0;
- //Apply palette
- //color = GetDitheredPalette(shade, pixel);
- vec3 color = vec3( hsv2rgb(vec3(shade, shade, shade)).rgb );
- //color = mix(color, vec3(0.1), step(22.0, length(position)));
- return color;
- }
- */
- const char* shader_vertex = R"GLSL(
- #version 330 core
- // This way, the entire canvas is covered with a single triangle
- const vec2 verts[3] = vec2[](
- vec2(-1.0f, -1.0f), // Bottom-left
- vec2( 3.0f, -1.0f), // Bottom-right (horizontally past NDC)
- vec2(-1.0f, 3.0f) // Top-left (vertically past NDC)
- );
- out vec2 fragNDC;
- out vec2 fragCoords;
- uniform vec3 iResolution; // viewport resolution (in pixels)
- void main(){
- vec2 pos = verts[gl_VertexID];
- fragNDC = pos;
- fragCoords = ((pos+1.0)/2.0) * iResolution.xy;
- gl_Position = vec4(pos, 0.0f, 1.0f);
- }
- )GLSL";
- // maybe use the velX and velY bits for something?
- const char* shader_fragment = R"GLSL(
- #version 330 core
- #define METABALL_THRESHHOLD 75.0
- in vec2 fragNDC;
- in vec2 fragCoords;
- out vec4 fragColor;
- uniform samplerBuffer spheres;
- uniform int spheres_len;
- uniform float threshhold;
- uniform vec3 iResolution; // viewport resolution (in pixels)
- uniform vec4 iMouse; // mouse pixel coords. xy: current (if MLB down), zw: click
- uniform float iTime; // shader playback time (in seconds)
- // When input is < 1.0, output is v
- // When input is 1.0-1.99..., output is 2.0-v
- // (Its output basically looks like a triangle wave)
- float oscillate(float v){
- return 1.0 - abs(1.0-mod(v, 2.0));
- }
- // All values are normalized
- vec3 hsv2rgb(vec3 c){
- vec4 K = vec4(1.0, 2.0/3.0, 1.0/3.0, 3.0);
- vec3 p = abs(fract(c.xxx+K.xyz) * 6.0 - K.www);
- return c.z * mix(K.xxx, clamp(p-K.xxx, 0.0, 1.0), c.y);
- }
- float distMag(vec2 p0, vec2 p1, float mag){
- p0 -= p1;
- float result = sqrt(p0.x*p0.x + p0.y*p0.y);
- return mag / (result*result);
- }
- // Returns a multiplier of how far past the threshhold the sum is
- float sumMetaballs(){
- float sum = 0.0;
- for(int i=0; i<spheres_len; ++i){
- vec4 metaball = texelFetch(spheres, i);
- sum += distMag(fragCoords, metaball.xy, metaball.w);
- }
- return sum/threshhold;
- }
- void main(){
- float shade = oscillate(sumMetaballs()/4.0);
- float shadeTimed = oscillate(sumMetaballs()/4.0 + iTime/10.0);
- vec3 hsv = vec3(shadeTimed, 1.0/shadeTimed, float(shade>0.05));
- vec3 rgb = hsv2rgb(hsv);
- fragColor = vec4(rgb, 1.0);
- }
- )GLSL";
- //maybe make color proportional to its size?
- /*
- const char* shader_fragment = R"GLSL(
- #version 330 core
- #define ENABLE_DITHER 0
- #define MAX_STEPS 200
- #define MIN_DIST 0.002
- in vec2 fragNDC;
- out vec4 fragColor;
- uniform samplerBuffer spheres;
- uniform int spheres_len;
- uniform float fractTime; // 0.0 -> 0.99...
- uniform vec2 camAngle;
- uniform vec3 camPos;
- // When input is < 1.0, output is v
- // when input is 1.0-1.99..., output is 2.0-v
- float oscillate(float v){
- return 1.0 - abs(1.0-mod(v, 2.0));
- }
- mat2 rotate(float angleRadians){
- return mat2( cos(angleRadians), sin(angleRadians),
- -sin(angleRadians), cos(angleRadians));
- }
- vec3 hsv2rgb(vec3 c){
- vec4 K = vec4(1.0, 2.0/3.0, 1.0/3.0, 3.0);
- vec3 p = abs(fract(c.xxx+K.xyz) * 6.0 - K.www);
- return c.z * mix(K.xxx, clamp(p-K.xxx, 0.0, 1.0), c.y);
- }
- float sdfSphere(vec3 pos, vec4 sphere){
- return length(pos-sphere.xyz) - sphere.w; // (.w is its radius)
- }
- float sdfScene(vec3 pos){
- float dist = 1e20; // Big starting distance
- for(int i=0; i<spheres_len; ++i){
- vec4 sphere = texelFetch(spheres, i);
- dist = min(dist, sdfSphere(pos, sphere));
- }
- return dist;
- }
- // Returns point of contact, or a max distance ray if nothing was hit
- vec3 rayMarch(vec3 origin, vec3 direction){
- float hitDist = 0.0;
- for(int i=0; i<MAX_STEPS; ++i){
- float sceneDist = sdfScene(origin + direction*hitDist);
- if(sceneDist < MIN_DIST) break;
- hitDist += sceneDist;
- }
- return origin + direction*hitDist;
- }
- #define LIGHT_MAX_DIST 32.0
- float getShade(vec3 pos, vec3 posLight){
- float dist = length(pos-posLight);
- //float shade = 1.0f * float(dist<LIGHT_MAX_DIST);
- float shade = ((LIGHT_MAX_DIST)-dist)/(LIGHT_MAX_DIST);
- shade = clamp(shade, 0.0, 1.0);
- #define GAMMA 0.087890625
- shade = pow(shade, 1.0/(GAMMA));
- shade = 1.0f/dist;
- return shade;
- }
- void main(){
- vec2 aspectRatio = vec2(16.0/9.0, 1.0);
- vec2 fragCoords = (fragNDC+1.0)/2.0;
- vec2 xy = fragCoords; // * tan(fovRadians * 0.5);
- vec3 rayOrigin = camPos;
- vec3 rayDir = normalize(vec3(xy - aspectRatio/2.0, 1.0));
- mat2 camRotX = rotate(camAngle.x);
- mat2 camRotY = rotate(camAngle.y);
- rayOrigin.yz *= camRotX;
- rayOrigin.xz *= camRotY;
- rayDir.yz *= camRotX;
- rayDir.xz *= camRotY;
- vec3 contactPoint = rayMarch(rayOrigin, rayDir);
- float shade = getShade(contactPoint, rayOrigin);
- fragColor = vec4(shade, shade, shade, 1.0);
- }
- )GLSL";
- */
- // Assumes prefix has already been copied to infoLogBuffer
- void concatenateInfoBuffer(const char* prefix_str){
- strnCpy(infoLogBuffer, prefix_str, sizeof(infoLogBuffer)-1);
- strnCat(infoLogBuffer, ": ", sizeof(infoLogBuffer)-1);
- strnCat(infoLogBuffer, infoLogPostfix, sizeof(infoLogBuffer)-1);
- infoLogBuffer[sizeof(infoLogBuffer)-1] = 0; // Just in case
- }
- void assertShaderComp(GLuint shader_id, const char* prefix_str){
- int success;
- glGetShaderiv(shader_id, GL_COMPILE_STATUS, &success);
- if(!success){
- glGetShaderInfoLog(shader_id,sizeof(infoLogPostfix),nullptr,infoLogPostfix);
- concatenateInfoBuffer(prefix_str);
- throw (const char*)infoLogBuffer;
- }
- }
- void assertShaderProg(GLuint program_id, const char* prefix_str){
- int success;
- glGetProgramiv(program_id, GL_LINK_STATUS, &success);
- if(!success){
- glGetProgramInfoLog(program_id, sizeof(infoLogPostfix),
- nullptr, infoLogPostfix);
- concatenateInfoBuffer(prefix_str);
- throw (const char*)infoLogBuffer;
- }
- }
- GLuint createShaderProg(const char** SRC_vert_shader_p,
- const char** SRC_frag_shader_p,
- const char* failure_string = nullptr)
- {
- if(SRC_vert_shader_p == nullptr)
- throw "createShaderProg(): SRC_vert_shader_p = nullptr";
- if(SRC_frag_shader_p == nullptr)
- throw "createShaderProg(): SRC_frag_shader_p = nullptr";
- if(failure_string == nullptr)
- failure_string = "Failed to create shader program";
- // Make vertex shader
- GLuint ID_vert_shader = glCreateShader(GL_VERTEX_SHADER);
- if(!ID_vert_shader) throw "\"glCreateShader(GL_VERTEX_SHADER)\" failed";
- glShaderSource(ID_vert_shader, 1, SRC_vert_shader_p, nullptr);
- glCompileShader(ID_vert_shader);
- assertShaderComp(ID_vert_shader, "Failed to compile vertex shader");
- // Make fragment shader
- GLuint ID_frag_shader = glCreateShader(GL_FRAGMENT_SHADER);
- if(!ID_frag_shader) throw "\"glCreateShader(GL_FRAGMENT_SHADER)\" failed";
- glShaderSource(ID_frag_shader, 1, SRC_frag_shader_p, nullptr);
- glCompileShader(ID_frag_shader);
- assertShaderComp(ID_frag_shader, "Failed to compile fragment shader");
- // Make program
- GLuint ID_shader_program = glCreateProgram();
- if(!ID_frag_shader) throw "\"glCreateProgram()\" failed";
- glAttachShader(ID_shader_program, ID_vert_shader);
- glAttachShader(ID_shader_program, ID_frag_shader);
- glLinkProgram(ID_shader_program);
- assertShaderProg(ID_shader_program, failure_string);
- glDeleteShader(ID_vert_shader);
- glDeleteShader(ID_frag_shader);
- return ID_shader_program;
- }
- f32 velocities[65536]; // LUT of velocities
- sphere* spheres;
- GLint spheres_len;
- Point2d resolution;
- #define THRESHHOLD_RATIO (75.0f/400)
- f32 threshhold = 0.0001f;
- #define MBCOUNT_FRACT(x,y) ((f32)spheres_len*((f32)(x)/(y)))
- void rem_metaball(){
- //spheres_len = MAX(spheres_len-1, 0);
- spheres_len = MAX(spheres_len-1, 1);
- //for(GLint i=0; i<spheres_len; ++i)
- // spheres[i].m = MBCOUNT_FRACT(1.0f,4) + MBCOUNT_FRACT(3.0f,4)*frandf();
- //threshhold = ((f32)spheres_len)*THRESHHOLD_RATIO;
- }
- void add_metaball(f32 x, f32 y){
- if(spheres_len >= MAX_SPHERE_COUNT) return;
- u16 velX_new = frandf()*65535;
- u16 velY_new = frandf()*65535;
- // y is inverted, due to how OpenGL NDCs work
- spheres[spheres_len].x = x;
- spheres[spheres_len].y = resolution.y-y;
- spheres[spheres_len].velX.u = (velX_new!=32768) ? velX_new : 32769;
- spheres[spheres_len].velY.u = (velY_new!=32768) ? velY_new : 32769;
- //for(GLint i=0; i<spheres_len; ++i)
- // spheres[i].m = MBCOUNT_FRACT(1.0f,4) + MBCOUNT_FRACT(3.0f,4)*frandf();
- spheres[spheres_len].m = MBCOUNT_FRACT(1.0f,4)+MBCOUNT_FRACT(3.0f,4)*frandf();
- ++spheres_len;
- //threshhold = ((f32)spheres_len)*THRESHHOLD_RATIO;
- }
- void animate_metaballs(){
- #define OPTIMAL_FRAME (1000.0/62.5) // 16ms
- #define COEFFICIENT_DIV (1.0/OPTIMAL_FRAME)
- #define LASTTIME_START 0xFFFFFFFFFFFFFFFF // = 2^64 - 1
- static u64 timeLast = LASTTIME_START;
- const u64 timeThis = timeGetPerfCounter();
- if(timeLast == LASTTIME_START) timeLast = timeThis;
- // Note: convert to f64 if too many rounding errors start happening
- const f32 timeDelta = (f32)(timeThis-timeLast)/timeGetPerfFreq();
- timeLast = timeThis;
- for(int i=0; i<spheres_len; ++i){
- // Note: convert to f64 if too many rounding errors start happening
- const f32 coefficient = timeDelta*COEFFICIENT_DIV;
- sphere& metaball = spheres[i];
- metaball.x += velocities[metaball.velX.u]*coefficient;
- metaball.y += velocities[metaball.velY.u]*coefficient;
- if(metaball.x<0 || metaball.x>=resolution.x){
- metaball.velX.s = -metaball.velX.s;
- metaball.x = CLAMP(metaball.x, 0, resolution.x-1);
- }
- if(metaball.y<0 || metaball.y>=resolution.y){
- metaball.velY.s = -metaball.velY.s;
- metaball.y = CLAMP(metaball.y, 0, resolution.y-1);
- }
- }
- }
- #define SET_TICKCOUNT (tickCount=((s64)timeGetPerfCounter()))
- int user_main(int argc, char** argv){
- s64 tickCount; SET_TICKCOUNT;
- s64 ticksPerSecond = (s64)timeGetPerfFreq();
- f64 timeStart = (f64)tickCount/ticksPerSecond; // Doesn't change
- // Calculate velocities LUT
- for(s32 i=0; i<65536; ++i){
- r16 j; j.u = i&65535;
- if(j.s==-32768) continue;
- velocities[j.u] = MAX_METABALL_SPEED*((f32)j.s/32767);
- }
- // Otherwise (signed) index -32768 would stay 0
- velocities[32768] = velocities[32769];
- // Set up viewport, and compile and link shaders
- resolution = get_win_size();
- glViewport(0, 0, resolution.x, resolution.y);
- u32 ID_prg_raymarch = createShaderProg(&shader_vertex, &shader_fragment,
- "Failed to create main shader program");
- // mem_Wrapper should free automatically, even if an exception is thrown
- mem_Wrapper sceneBuffer((MAX_SPHERE_COUNT) * sizeof(sphere));
- spheres = (sphere*)sceneBuffer.ptr;
- spheres_len = 0;
- if(spheres == nullptr) throw "Failed to allocate scene data buffer";
- u32 ID_VAO, ID_TBO, ID_TEX;
- glGenVertexArrays(1, &ID_VAO);
- glBindVertexArray(ID_VAO); // Never unbound
- // Create the actual Texture-Buffer-Object
- glGenBuffers(1, &ID_TBO);
- glBindBuffer(GL_TEXTURE_BUFFER, ID_TBO);
- // Allocate buffer with GL_DYNAMIC_DRAW usage hint
- // (without copying anything initially!)
- glBufferData(GL_TEXTURE_BUFFER, (MAX_SPHERE_COUNT) * sizeof(sphere),
- nullptr, GL_DYNAMIC_DRAW);
- // Associate a texture to that TBO...
- glGenBuffers(1, &ID_TEX);
- glBindTexture(GL_TEXTURE_BUFFER, ID_TEX);
- // ...while specifying its format, GL_RGBA32F
- glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, ID_TBO);
- GLint UNI_spheres_len = glGetUniformLocation(ID_prg_raymarch, "spheres_len");
- GLint UNI_threshhold = glGetUniformLocation(ID_prg_raymarch, "threshhold");
- GLint UNI_iTime = glGetUniformLocation(ID_prg_raymarch, "iTime");
- GLint UNI_iResolution = glGetUniformLocation(ID_prg_raymarch, "iResolution");
- GLint UNI_iMouse = glGetUniformLocation(ID_prg_raymarch, "iMouse");
- glUseProgram(ID_prg_raymarch);
- #ifdef _DEBUG
- s64 timeDeltaTicks = ((s64)timeGetPerfCounter())-tickCount;
- f64 timeDeltaSecs = (f64)timeDeltaTicks/ticksPerSecond;
- _printf("Setting up OpenGL shaders & buffers took an additional: %.4f seconds!\n", timeDeltaSecs);
- #endif
- //trap_cursor(true, true);
- Fpoint2d mpos = {0.0f, 0.0f};
- add_metaball(frand()*(resolution.x-1), frand()*(resolution.y-1));
- while(!is_win_closed()){
- SET_TICKCOUNT;
- s64 truncTimeTicks = tickCount/ticksPerSecond;
- s64 fractTimeTicks = tickCount%ticksPerSecond;
- f64 timeSeconds = ((f64)truncTimeTicks)+((f32)fractTimeTicks/ticksPerSecond);
- timeSeconds -= timeStart;
- f32 timeSeconds32 = (f32)timeSeconds;
- //Handle events
- Event evt;
- while(pollEvent(&evt))
- switch(evt.type){
- case EVENT_KEY_DOWN: {
- if(evt.key.vkey == VKEY_ESCAPE) close_window();
- } break;
- case EVENT_MOUSE_MOVED: {
- mpos.x = evt.mouse.x;
- mpos.y = evt.mouse.y;
- //_printf("%f, %f\n", mpos.x, mpos.y);
- } break;
- case EVENT_MOUSE_DOWN: {
- if(evt.mouse.button&MBUTTON_LEFT)
- add_metaball(evt.mouse.x, evt.mouse.y);
- else
- rem_metaball();
- } break;
- case EVENT_MOUSE_VWHEEL: {
- threshhold = MAX(threshhold+(evt.mouse.dy/700000),
- 0.00000000004843059082f); // Small, but not 0
- _printf("%f\n", threshhold);
- } break;
- }
- if(is_win_closed()) break;
- // Update uniform values
- glUniform1i(UNI_spheres_len, spheres_len);
- glUniform1f(UNI_threshhold, threshhold);
- glUniform1f(UNI_iTime, timeSeconds32);
- glUniform3f(UNI_iResolution, (f32)resolution.x, (f32)resolution.y, 1.0f);
- glUniform4f(UNI_iMouse, mpos.x, mpos.y, mpos.x, mpos.y);
- // Upload the scene data to the TBO
- glBindBuffer(GL_TEXTURE_BUFFER, ID_TBO);
- glBufferSubData(GL_TEXTURE_BUFFER, 0, sizeof(sphere)*spheres_len, spheres);
- // Draw stuff (only if the window is in focus)
- if(is_win_focused()){
- // 3 vertex indices for a single triangle, starting at index 0
- // (using glClear should be redundant here, given that
- // the only triangle used completely covers the screen!)
- glDrawArrays(GL_TRIANGLES, 0, 3);
- present_window();
- }
- animate_metaballs();
- // Waits for about 16ms to approximate 60fps
- timeSleep(16);
- }
- // Optional de-allocation
- //glDeleteTextures(1, &ID_TEX);
- glDeleteBuffers(1, &ID_TBO);
- glDeleteVertexArrays(1, &ID_VAO);
- glDeleteProgram(ID_prg_raymarch);
- return 0;
- }
- /******************************************************************************/
- /******************************************************************************/
- //"opengl_metaballs_2025-06-26\src\kit_utils\misc\is_bit_set.cpp":
- #include <public_stuff.hpp>
- // Union type punning in C++ is technically undefined behavior,
- // however GCC (if I recall correctly) explicitly allows it as an extension.
- #define USE_UNION_TYPE_PUNNING 1
- #if USE_UNION_TYPE_PUNNING == 1
- bool is_bit_set(const void* buffer, u32 which_bit){
- union {
- u32 value;
- struct {
- u32 bit : 3;
- u32 byte : 29;
- };
- } _which_bit;
- _which_bit.value = which_bit;
- return 1&( (((u8*)buffer)[_which_bit.byte]) >> _which_bit.bit );
- }
- #else
- bool is_bit_set(const void* buffer, u32 which_bit) {
- const u8* bytes = static_cast<const u8*>(buffer);
- u32 byte_index = which_bit / 8;
- u32 bit_index = which_bit % 8;
- return (bytes[byte_index] >> bit_index) & 1;
- }
- #endif
- /******************************************************************************/
- /******************************************************************************/
- //"opengl_metaballs_2025-06-26\src\kit_utils\misc\kit_misc.cpp":
- #include <public_stuff.hpp>
- #ifdef FRAND_USED
- #include <stdlib.h>
- #if RAND_MAX == 32767
- #define GET_FRAND_VALUE() ( (double)(rand()<<15|rand())/0x3FFFFFFF )
- #elif RAND_MAX == 2147483647
- #define GET_FRAND_VALUE() ( (double)rand()/0x7FFFFFFF )
- #else
- #error "No definition of GET_FRAND_VALUE() available for current RAND_MAX"
- #endif
- f64 frand(){ //0.0f -> 1.0f
- return GET_FRAND_VALUE();
- }
- f64 frand2(){ //-1.0f -> 1.0f
- return GET_FRAND_VALUE()*2.0f - 1.0f;
- }
- f32 frandf(){ //0.0f -> 1.0f
- return (f32)GET_FRAND_VALUE();
- }
- f32 frandf2(){ //-1.0f -> 1.0f
- return (f32)GET_FRAND_VALUE()*2.0f - 1.0f;
- }
- #endif
- //...
- /******************************************************************************/
- /******************************************************************************/
- //"opengl_metaballs_2025-06-26\src\kit_utils\misc\print_event.cpp":
- #include <public_stuff.hpp>
- #ifdef PRINT_EVENT_USED
- #ifdef _DEBUG
- static char key_evt_text[][5] = { // EVENT_KEY_?
- "NULL",
- "CHAR",
- "UP",
- "DOWN",
- };
- static char mouse_evt_text[][7] = { // EVENT_MOUSE_?
- "NULL",
- "MOVED",
- "HWHEEL",
- "VWHEEL",
- "UP",
- "DOWN",
- };
- static char cursor_evt_text[][9] = { // EVENT_CURSOR_?
- "NULL",
- "TRAPPED",
- "RELEASED",
- };
- void print_event(Event& evt){
- u16 subevent = SUBEVENT_ID(evt.type);
- switch(EVENT_ID(evt.type)){
- case EVENT_NULL:
- {
- _printf("EVENT_NULL = {\n");
- _printf(" .type = EVENT_NULL,\n");
- _printf(" .timestamp = %llu,\n", evt.common.timestamp);
- } break;
- case EVENT_COMMON:
- {
- _printf("EVENT_COMMON = {\n");
- _printf(" .type = EVENT_COMMON,\n");
- _printf(" .timestamp = %llu,\n", evt.common.timestamp);
- } break;
- case EVENT_QUIT:
- {
- _printf("EVENT_COMMON = {\n");
- _printf(" .type = EVENT_COMMON,\n");
- _printf(" .timestamp = %llu,\n", evt.common.timestamp);
- } break;
- case EVENT_KEY:
- {
- _printf("EVENT_KEY = {\n");
- _printf(" .type = EVENT_KEY_%s,\n", key_evt_text[subevent]);
- _printf(" .timestamp = %llu,\n\n", evt.key.timestamp);
- _printf(" .kmods = 0x%04X = {\n", evt.key.kmods);
- _printf(" .lshift = %i,\n", evt.key.sym.kmod.lshift);
- _printf(" .rshift = %i,\n", evt.key.sym.kmod.rshift);
- _printf(" .lctrl = %i,\n", evt.key.sym.kmod.lctrl);
- _printf(" .rctrl = %i,\n", evt.key.sym.kmod.rctrl);
- _printf(" .lalt = %i,\n", evt.key.sym.kmod.lalt);
- _printf(" .ralt = %i,\n", evt.key.sym.kmod.ralt);
- _printf(" .lgui = %i,\n", evt.key.sym.kmod.lgui);
- _printf(" .rgui = %i,\n", evt.key.sym.kmod.rgui);
- _printf(" .numlock = %i,\n", evt.key.sym.kmod.numlock);
- _printf(" .capslock = %i,\n", evt.key.sym.kmod.capslock);
- _printf(" .altgraph = %i,\n", evt.key.sym.kmod.altgraph);
- _printf(" .scrollock = %i,\n", evt.key.sym.kmod.scrollock);
- _printf(" }\n\n");
- _printf(" .pkey = 0x%02X,\n", evt.key.pkey);
- _printf(" .vkey = 0x%02X,\n", evt.key.vkey);
- _printf(" .pressed = %s,\n", BOOL_STR(evt.key.pressed));
- _printf(" .ischar = %s,\n", BOOL_STR(evt.key.ischar));
- _printf(" .repeat = %s,\n", BOOL_STR(evt.key.repeat));
- } break;
- case EVENT_MOUSE:
- {
- _printf("EVENT_MOUSE = {\n");
- _printf(" .type = EVENT_MOUSE_%s,\n\n", mouse_evt_text[subevent]);
- _printf(" .button = 0x%02X,\n", evt.mouse.button);
- _printf(" .pressed = %s,\n", BOOL_STR(evt.mouse.pressed));
- _printf(" .dblClick = %s,\n\n", BOOL_STR(evt.mouse.dblClick));
- _printf(" .timestamp = %llu,\n\n", evt.mouse.timestamp);
- _printf(" .x = %5.2f,\n", evt.mouse.x);
- _printf(" .y = %5.2f,\n", evt.mouse.y);
- _printf(" .dx = %5.2f,\n", evt.mouse.dx);
- _printf(" .dy = %5.2f,\n", evt.mouse.dy);
- } break;
- case EVENT_CURSOR:
- {
- _printf("EVENT_CURSOR = {\n");
- _printf(" .type = EVENT_CURSOR_%s,\n", cursor_evt_text[subevent]);
- _printf(" .timestamp = %llu,\n", evt.common.timestamp);
- } break;
- default:
- {
- _printf("EVENT_UNKNOWN = {\n");
- _printf(" .type = 0x%08X,\n", evt.type);
- _printf(" .timestamp = %llu,\n", evt.common.timestamp);
- }
- }
- _printf("}\n");
- }
- #endif /* _DEBUG */
- #endif /* PRINT_EVENT_USED */
- /******************************************************************************/
- /******************************************************************************/
- //"opengl_metaballs_2025-06-26\src\kit_utils\misc\snPrintf.cpp":
- #include <public_stuff.hpp>
- #undef snprintf
- #undef vsnprintf
- #define STB_SPRINTF_IMPLEMENTATION
- #include "../../../dep/stb_sprintf.h"
- s32 snPrintf(char* str_dst, size_t len_max, const char* str_fmt, ...){
- va_list va;
- va_start(va, str_fmt);
- s32 result = 0;
- if(len_max > 0 && len_max <= INT_MAX){
- result = stbsp_vsnprintf(str_dst, (int)len_max, str_fmt, va);
- } else {
- result = stbsp_vsprintf(str_dst, str_fmt, va);
- }
- va_end(va);
- return result;
- }
- s32 vsnPrintf(char* str_dst, size_t len_max, const char* str_fmt, va_list va){
- if(len_max > 0 && len_max <= INT_MAX){
- return stbsp_vsnprintf(str_dst, (int)len_max, str_fmt, va);
- } else {
- return stbsp_vsprintf(str_dst, str_fmt, va);
- }
- }
- /******************************************************************************/
- /******************************************************************************/
- //"opengl_metaballs_2025-06-26\src\kit_utils\sound\AudioData.cpp":
- #include <public_stuff.hpp>
- #ifdef SOUND_STUFF_USED
- void AudioDataHeader::printHeader(const char* name){
- if(name != nullptr){ _printf("%s = {\n", name); }
- else { _printf("%p = {\n", this); }
- #ifdef _DEBUG
- _printf(" ->magic = \"%.4s\"; (0x%08X)\n", (char*)&magic, magic);
- const char* fmt_txt = "?";
- switch(format){
- case SMPFMT_U8 : fmt_txt = "U8"; break;
- case SMPFMT_S8 : fmt_txt = "S8"; break;
- case SMPFMT_U16LSB: fmt_txt = "U16LSB"; break;
- case SMPFMT_S16LSB: fmt_txt = "S16LSB"; break;
- case SMPFMT_S24LSB: fmt_txt = "S24LSB"; break;
- case SMPFMT_S32LSB: fmt_txt = "S32LSB"; break;
- case SMPFMT_F32LSB: fmt_txt = "F32LSB"; break;
- case SMPFMT_F64LSB: fmt_txt = "F64LSB"; break;
- case SMPFMT_U16MSB: fmt_txt = "U16MSB"; break;
- case SMPFMT_S16MSB: fmt_txt = "S16MSB"; break;
- case SMPFMT_S24MSB: fmt_txt = "S24MSB"; break;
- case SMPFMT_S32MSB: fmt_txt = "S32MSB"; break;
- case SMPFMT_F32MSB: fmt_txt = "F32MSB"; break;
- case SMPFMT_F64MSB: fmt_txt = "F64MSB"; break;
- default : fmt_txt = "UNKNOWN";
- }
- _printf(" ->format = SMPFMT_%s; (0x%04X)\n", fmt_txt, format);
- _printf(" ->headerSize = %u;\n", headerSize);
- _printf(" ->dataSize = %llu;\n", dataSize);
- _printf(" ->loopStart = %llu;\n", loopStart);
- _printf(" ->loopEnd = %llu;\n", loopEnd);
- _printf(" ->numSamples = %llu;\n", numSamples);
- _printf(" ->sampleRate = %u;\n", sampleRate);
- _printf(" ->bitRate = %u;\n", bitRate);
- _printf(" ->loopCount = %u;\n", loopCount);
- _printf(" ->channels = %u;\n", channels);
- _printf(" ->_reserved = %u;\n", _reserved);
- _printf(" ->fmt_version = %u;\n", fmt_version);
- _printf(" ->mode = %u;\n", mode);
- _printf(" ->metadata_type = %u;\n", metadata_type);
- _printf(" ->samples = %p;\n", samples);
- _printf(" ->userdata = %p;\n", userdata);
- _printf("};");
- #else
- _printf(" (AudioDataHeader::printHeader() is not available in release build!)\n}\n");
- #endif /* _DEBUG */
- }
- bool AudioData::_allocate_hdr(u16 headerSize, u64 dataSize){
- if(hdr) return false;
- if(headerSize < sizeof(AudioDataHeader)) return false;
- hdr = (AudioDataHeader*)mem_alloc(headerSize+dataSize);
- if(hdr == nullptr) return false;
- mem_set(hdr, 0, headerSize+dataSize);
- hdr->magic = KPM_FILE_SIG;
- hdr->headerSize = headerSize;
- hdr->dataSize = dataSize;
- hdr->samples = (u8*)hdr + hdr->headerSize;
- return true;
- }
- AudioData::AudioData(AudioSampleFormatEnum format,
- u64 numSamples, u16 channels, u32 sampleRate)
- {
- if(hdr) return;
- const u64 dataSize = GET_AUDIO_BYTESIZE(format)*numSamples*channels;
- if(!_allocate_hdr(sizeof(AudioDataHeader), dataSize)) return;
- // (Redundant assignments are commented out here)
- //hdr->magic = KPM_FILE_SIG;
- hdr->format = format;
- //hdr->headerSize = sizeof(AudioDataHeader);
- //hdr->dataSize = dataSize;
- //hdr->loopStart = 0;
- hdr->loopEnd = numSamples;
- hdr->numSamples = numSamples;
- hdr->sampleRate = sampleRate;
- hdr->bitRate = GET_AUDIO_BITSIZE(format)*sampleRate*channels;
- //hdr->loopCount = 0;
- hdr->channels = channels;
- //hdr->_reserved = 0;
- hdr->fmt_version = 1; // 1 indicates the version kit_sdl2 uses
- //hdr->mode = 0; // PCM or float data
- //hdr->metadata_type = 0; // No metadata
- //hdr->samples = (u8*)hdr + hdr->headerSize;
- //hdr->userdata = nullptr;
- }
- #ifdef AUDIODATA_FILELOAD_USED
- #define KPCM_FILE_SIG 0x4D43506B //.kpm's old file signature
- AudioData::AudioData(const char* filePath,
- AudioDataLoaderCallback callback)
- {
- if(hdr) return;
- if(filePath == nullptr) return;
- if(!fileio_exists(filePath)) return;
- AudioDataHeader* _hdr;
- if(callback == nullptr){ // Load .kpm file
- size_t fileSize;
- _hdr = (AudioDataHeader*)fileio_read(filePath, &fileSize);
- if(_hdr == nullptr) return;
- // Check for the current and old version of .kpm's file signature
- // (but only if the fileSize is enough for a u32)
- if(fileSize >= sizeof(u32) &&
- (_hdr->magic != KPM_FILE_SIG && _hdr->magic != KPCM_FILE_SIG))
- {
- _free_hdr_copy: mem_free(&_hdr); return;
- }
- else if(fileSize < sizeof(AudioDataHeader)) goto _free_hdr_copy;
- /*
- if(_hdr->magic != KIT_MAGIC_KPM) throw "magic != KIT_MAGIC_KPM";
- if(!isFormatValid(_hdr->format)) throw "format is invalid";
- if(_hdr->headerSize < sizeof(AudioDataHeader)) throw "headerSize < sizeof(AudioDataHeader)";
- if(_hdr->dataSize != (fileSize-_hdr->headerSize)) throw "dataSize is invalid";
- //(channels are checked before numSamples to prevent divide-by-zero exceptions)
- if(_hdr->channels!=1 && _hdr->channels!=2) throw "audio is neither mono nor stereo";
- //(numSamples is checked before loopStart/loopEnd, as their checks rely upon numSamples)
- if(_hdr->numSamples != (_hdr->dataSize/KIT_ASTREAM_FMT_BYTESIZE(_hdr->format))/_hdr->channels) throw "numSamples is invalid";
- if(_hdr->loopStart >= _hdr->numSamples) throw "loopStart >= numSamples";
- if(_hdr->loopEnd > _hdr->numSamples) throw "loopEnd > numSamples";
- if(_hdr->sampleRate < 1000) throw "sampleRate < 1000";
- if(_hdr->bitRate != _hdr->sampleRate*_hdr->channels*KIT_ASTREAM_FMT_BITSIZE(_hdr->format)) throw "bitRate is invalid";
- if(_hdr->bitRemainder != 0) throw "bitRemainder != 0";
- if(_hdr->mode != 0) throw "only mode 0 kPCM files are currently supported";
- */
- // The only difference between 0 and 1 is that bitsPerSample is offset by -1
- if(_hdr->fmt_version == 0) ++_hdr->format;
- _hdr->magic = KPM_FILE_SIG; // If it was previously kPCM, now it is kPxM
- _hdr->fmt_version = 1;
- } else {
- _hdr = callback(filePath);
- if(_hdr == nullptr) return;
- }
- size_t totalSize = _hdr->headerSize + _hdr->dataSize;
- hdr = (AudioDataHeader*)mem_alloc(totalSize);
- if(hdr == nullptr){ mem_free(&_hdr); return; }
- mem_copy(hdr, _hdr, totalSize);
- mem_free(&_hdr);
- hdr->samples = (u8*)hdr + hdr->headerSize;
- }
- #endif /* AUDIODATA_FILELOAD_USED */
- AudioData::~AudioData(){
- mem_free(&hdr);
- }
- #ifdef AUDIODATA_SAVEAUDIO_USED
- bool AudioData::saveAudio(const char* filePath,
- AudioDataSaverCallback callback)
- {
- if(hdr == nullptr) return false;
- if(filePath == nullptr) return false;
- if(callback == nullptr){ //save .kpm
- if(!fileio_write(filePath, hdr, hdr->headerSize+hdr->dataSize))
- return false;
- } else {
- if(!callback(filePath, *hdr))
- return false;
- }
- return true;
- }
- #endif
- #ifdef AUDIODATA_CONVERTFORMAT_USED
- static bool _fmt_is_valid(u16 fmt){
- switch(fmt){
- case SMPFMT_U8 :
- case SMPFMT_S8 :
- case SMPFMT_U16:
- case SMPFMT_S16:
- case SMPFMT_S24:
- case SMPFMT_S32:
- case SMPFMT_F32:
- case SMPFMT_F64: return true; // Lol
- default: return false;
- }
- }
- // = 2^(bits-1)
- #define ABS_S8_MIN (128) //ABS_Sx_MIN is a horrible name for this,
- #define ABS_S16_MIN (32768) //but it's the name i chose within 10 seconds
- #define ABS_S24_MIN (8388608) //(so i may or may not change it, idk)
- #define ABS_S32_MIN (2147483648)
- struct _s24 { u8 a, b, c; } //mostly for memory alignment purposes
- ATTR_PACKED; //(explicitly pack just in case; probably unnecessary)
- union _s24u {
- _s24 v;
- s32 n : 24;
- inline _s24u(_s24 _v) : v(_v) {}
- inline _s24u(s32 _n) : n(_n&0x7FFFFF) {}
- };
- static inline f64 frm_s24(_s24 x){ return (f64)_s24u(x).n/ABS_S24_MIN; }
- static inline _s24 to_s24(f64 x){ return _s24u((s32)(x*0x7FFFFF)).v; }
- bool AudioData::convertFormat(AudioSampleFormatEnum format){
- if(hdr == nullptr) return false;
- if(hdr->format == format) return true;
- if(!_fmt_is_valid(hdr->format)) return false;
- if(!_fmt_is_valid(format)) return false;
- u64 totalSamples = hdr->numSamples*hdr->channels;
- u64 dataSize = GET_AUDIO_BYTESIZE(format)*totalSamples;
- u32 bitRate = GET_AUDIO_BITSIZE(format)*hdr->sampleRate*hdr->channels;
- mem_Wrapper temp_samples(totalSamples*sizeof(f64));
- f64* tmp = (f64*)temp_samples.ptr;
- void* smp = hdr->samples;
- #define FOR_TS_BRK(x) for(u64 i=0; i<totalSamples; ++i){ x; } break
- #define SMPCAST(_type) ( ((_type*)smp)[i] )
- #define FRM_CONV(_type, _scaling_factor, _modifier) \
- ( ((f64)SMPCAST(_type) _modifier) _scaling_factor )
- // Convert all source samples to 64-bit floats
- switch(hdr->format){
- case SMPFMT_U8 : FOR_TS_BRK( tmp[i] = FRM_CONV(u8 , /ABS_S8_MIN , -128) );
- case SMPFMT_S8 : FOR_TS_BRK( tmp[i] = FRM_CONV(s8 , /ABS_S8_MIN , ) );
- case SMPFMT_U16: FOR_TS_BRK( tmp[i] = FRM_CONV(u16, /ABS_S16_MIN, -32768) );
- case SMPFMT_S16: FOR_TS_BRK( tmp[i] = FRM_CONV(s16, /ABS_S16_MIN, ) );
- case SMPFMT_S24: FOR_TS_BRK( tmp[i] = frm_s24(SMPCAST(_s24)) );
- case SMPFMT_S32: FOR_TS_BRK( tmp[i] = FRM_CONV(s32, /ABS_S32_MIN, ) );
- case SMPFMT_F32: FOR_TS_BRK( tmp[i] = FRM_CONV(f32, , ) );
- case SMPFMT_F64: mem_copy(tmp, smp, hdr->dataSize); break;
- }
- //resize header to match destination format's dataSize
- if(!mem_realloc(&hdr, hdr->headerSize+dataSize)) return false;
- //update relevant header values
- hdr->format = format;
- hdr->dataSize = dataSize;
- hdr->bitRate = bitRate;
- hdr->samples = (u8*)hdr + hdr->headerSize;
- smp = hdr->samples;
- #define TO_CONV(_type, _scl_fct, _mod) ( (_type)( tmp[i] _scl_fct _mod ) )
- //convert the f64 samples to the desired format
- switch(hdr->format){ //(hdr->format = format now)
- case SMPFMT_U8 : FOR_TS_BRK( SMPCAST( u8 ) = TO_CONV(u8 , * 127, +128) );
- case SMPFMT_S8 : FOR_TS_BRK( SMPCAST( s8 ) = TO_CONV(s8 , * 127, ) );
- case SMPFMT_U16: FOR_TS_BRK( SMPCAST( u16) = TO_CONV(u16, *32767, +32768) );
- case SMPFMT_S16: FOR_TS_BRK( SMPCAST( s16) = TO_CONV(s16, *32767, ) );
- case SMPFMT_S24: FOR_TS_BRK( SMPCAST(_s24) = to_s24(tmp[i]) );
- case SMPFMT_S32: FOR_TS_BRK( SMPCAST( s32) = TO_CONV(s32, *0x7FFFFFFF, ) );
- case SMPFMT_F32: FOR_TS_BRK( SMPCAST( f32) = TO_CONV(f32, , ) );
- case SMPFMT_F64: mem_copy(smp, tmp, hdr->dataSize); break;
- }
- return true;
- }
- #endif
- #endif
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement