Lightning towards platonic, fix BAD qsort bugs

main
parent 291235e992
commit d190594b38

@ -18,7 +18,7 @@
// Intensive profiling means profiling a lot of little tiny stuff. Not always enabled because tanks performance
// #define INTENSIVE_PROFILING
// #define DEBUG_RENDERING
#define DEBUG_WORLD
// #define DEBUG_WORLD
// #define UNLOCK_ALL
#define TIME_BETWEEN_WORLD_SAVE 1000000.0f
// #define TIME_BETWEEN_WORLD_SAVE 1.0f
@ -26,7 +26,7 @@
#define DEBUG_TOOLS
#define CHIPMUNK_INTEGRITY_CHECK
// #define FAT_THRUSTERS
#define NO_GRAVITY
// #define NO_GRAVITY
// #define NO_SUNS
#else

Binary file not shown.

@ -350,8 +350,10 @@ static void raycast_query_callback(cpShape *shape, cpVect point, cpVect normal,
static THREADLOCAL cpVect from_point = {0};
static int sort_bodies_callback(const void *a, const void *b)
{
double a_dist = cpvdist(cpBodyGetPosition((cpBody *)a), from_point);
double b_dist = cpvdist(cpBodyGetPosition((cpBody *)b), from_point);
cpVect a_pos = cpBodyGetPosition(* (cpBody **)a);
cpVect b_pos = cpBodyGetPosition(* (cpBody **)b);
double a_dist = cpvdist(a_pos, from_point);
double b_dist = cpvdist(b_pos, from_point);
if (a_dist - b_dist < 0.0)
{
return -1;
@ -694,6 +696,29 @@ void box_create(GameState *gs, Entity *new_box, Entity *grid, cpVect pos, enum B
box_add_to_boxes(gs, grid, new_box);
}
int platonic_detection_compare(const void *a, const void *b)
{
PlatonicDetection *a_detection = (PlatonicDetection *)a;
PlatonicDetection *b_detection = (PlatonicDetection *)b;
double a_intensity = a_detection->intensity;
double b_intensity = b_detection->intensity;
if(a_detection->intensity == 0.0) a_intensity = INFINITY;
if(b_detection->intensity == 0.0) b_intensity = INFINITY;
double result = (a_intensity - b_intensity);
if (result < 0.0)
{
return -1;
}
else if (result > 0.0)
{
return 1;
}
else
{
return 0;
}
}
cpVect box_compass_vector(Entity *box)
{
@ -1572,6 +1597,11 @@ SerMaybeFailure ser_entity(SerState *ser, GameState *gs, Entity *e)
SER_MAYBE_RETURN(ser_f(ser, &e->currently_scanning_progress));
SER_VAR(&e->blueprints_learned);
SER_MAYBE_RETURN(ser_f(ser, &e->scanner_head_rotate));
for (int i = 0; i < SCANNER_MAX_PLATONICS; i++)
{
SER_MAYBE_RETURN(ser_V2(ser, &e->detected_platonics[i].direction));
SER_MAYBE_RETURN(ser_f(ser, &e->detected_platonics[i].intensity));
}
for (int i = 0; i < SCANNER_MAX_POINTS; i++)
{
SER_VAR(&e->scanner_points[i]);
@ -2407,8 +2437,8 @@ void create_initial_world(GameState *gs)
entity_set_pos(grid, cpv(1.5, 0.0));
BOX_AT_TYPE(grid, cpv(0.0, 0.0), BoxExplosive);
BOX_AT_TYPE(grid, cpv(-BOX_SIZE, 0.0), BoxScanner);
BOX_AT_TYPE(grid, cpv(-BOX_SIZE*2.0, 0.0), BoxSolarPanel);
BOX_AT_TYPE(grid, cpv(-BOX_SIZE*3.0, 0.0), BoxSolarPanel);
BOX_AT_TYPE(grid, cpv(-BOX_SIZE * 2.0, 0.0), BoxSolarPanel);
BOX_AT_TYPE(grid, cpv(-BOX_SIZE * 3.0, 0.0), BoxSolarPanel);
entity_ensure_in_orbit(gs, grid);
}
@ -2419,7 +2449,7 @@ void create_initial_world(GameState *gs)
BOX_AT_TYPE(grid, cpv(0.0, 0.0), BoxHullpiece);
entity_ensure_in_orbit(gs, grid);
}
#endif
#if 0 // merge box
@ -3218,26 +3248,32 @@ void process(struct GameState *gs, double dt)
{
for (int i = 0; i < SCANNER_MAX_POINTS; i++)
cur_box->scanner_points[i] = (struct ScannerPoint){0};
for (int i = 0; i < SCANNER_MAX_PLATONICS; i++)
cur_box->detected_platonics[i] = (PlatonicDetection){0};
if (cur_box->energy_effectiveness >= 1.0)
{
/*
cpVect from_pos = entity_pos(cur_box);
cpVect nearest = {0};
double nearest_dist = INFINITY;
PlatonicDetection detections[MAX_BOX_TYPES] = {0};
for (int i = 0; i < MAX_BOX_TYPES; i++)
{
cpVect cur_pos = gs->platonic_positions[i];
if (cpvlength(cur_pos) > 0.0) // zero is uninitialized, the platonic solid doesn't exist (probably) @Robust do better
{
double length_to_cur = cpvdist(from_pos, cur_pos);
if (length_to_cur < nearest_dist)
{
nearest_dist = length_to_cur;
nearest = cur_pos;
}
cpVect towards = cpvsub(cur_pos, from_pos);
double length_to_cur = cpvlength(towards);
detections[i].direction = cpvnormalize(towards);
detections[i].intensity = length_to_cur; // so it sorts correctly, changed to intensity correctly after sorting
}
}
qsort(detections, MAX_BOX_TYPES, sizeof(detections[0]), platonic_detection_compare);
for (int i = 0; i < SCANNER_MAX_PLATONICS; i++)
{
cur_box->detected_platonics[i] = detections[i];
if (cur_box->detected_platonics[i].intensity > 0.0)
{
cur_box->detected_platonics[i].intensity = max(0.1, 1.0 - clamp01(cur_box->detected_platonics[i].intensity / 100.0));
}
}
*/
circle_query(gs->space, entity_pos(cur_box), SCANNER_MAX_RANGE);
cpBody *body_results[512] = {0};
@ -3262,18 +3298,16 @@ void process(struct GameState *gs, double dt)
}
}
from_point = entity_pos(cur_box);
qsort(body_results, cur_results_len, sizeof(cpBody *), sort_bodies_callback);
size_t sizeof_element = sizeof(body_results[0]);
qsort(body_results, cur_results_len, sizeof_element, sort_bodies_callback);
size_t bodies_detected = cur_results_len < SCANNER_MAX_POINTS ? cur_results_len : SCANNER_MAX_POINTS;
for (int i = 0; i < bodies_detected; i++)
{
cpVect rel_vect = cpvsub(cpBodyGetPosition(body_results[i]), from_point);
double vect_length = cpvlength(rel_vect);
if (vect_length > SCANNER_MIN_RANGE)
if (SCANNER_MIN_RANGE < vect_length && vect_length < SCANNER_MAX_RANGE)
{
if (vect_length > SCANNER_MAX_VIEWPORT_RANGE)
{
rel_vect = cpvmult(cpvnormalize(rel_vect), SCANNER_MAX_RANGE);
}
cpVect radar_vect = cpvmult(cpvnormalize(rel_vect), clamp01(vect_length / SCANNER_MAX_VIEWPORT_RANGE));
enum ScannerPointKind kind = Platonic;
Entity *body_entity = cp_body_entity(body_results[i]);
@ -3297,10 +3331,13 @@ void process(struct GameState *gs, double dt)
{
kind = Enemy;
}
cpVect into_char_vect = cpvmult(radar_vect, 126.0);
flight_assert(fabs(into_char_vect.x) <= 126.0);
flight_assert(fabs(into_char_vect.y) <= 126.0);
cur_box->scanner_points[i] = (struct ScannerPoint){
.kind = (char)kind,
.x = (char)((rel_vect.x / SCANNER_MAX_VIEWPORT_RANGE) * 128.0),
.y = (char)((rel_vect.y / SCANNER_MAX_VIEWPORT_RANGE) * 128.0),
.x = (char)(into_char_vect.x),
.y = (char)(into_char_vect.y),
};
}
}

@ -0,0 +1,145 @@
@module horizontal_lightning
@vs vs
in vec4 coord;
out vec2 texUV;
void main() {
gl_Position = vec4(coord.xy, 0.0, 1.0);
texUV = coord.zw;
}
@end
@fs fs
uniform uniforms {
float iTime;
float alpha;
};
in vec2 texUV;
out vec4 fragColor;
vec4 permute(vec4 t) {
return t * (t * 34.0 + 133.0);
}
// Gradient set is a normalized expanded rhombic dodecahedron
vec3 grad(float hash) {
// Random vertex of a cube, +/- 1 each
vec3 cube = mod(floor(hash / vec3(1.0, 2.0, 4.0)), 2.0) * 2.0 - 1.0;
// Random edge of the three edges connected to that vertex
// Also a cuboctahedral vertex
// And corresponds to the face of its dual, the rhombic dodecahedron
vec3 cuboct = cube;
int selected_edge =int(hash / 16.0) ;
if(selected_edge == 0)
cuboct.x = 0.0;
if(selected_edge == 1)
cuboct.y = 0.0;
if(selected_edge == 2)
cuboct.z = 0.0;
// In a funky way, pick one of the four points on the rhombic face
float type = mod(floor(hash / 8.0), 2.0);
vec3 rhomb = (1.0 - type) * cube + type * (cuboct + cross(cube, cuboct));
// Expand it so that the new edges are the same length
// as the existing ones
vec3 grad = cuboct * 1.22474487139 + rhomb;
// To make all gradients the same length, we only need to shorten the
// second type of vector. We also put in the whole noise scale constant.
// The compiler should reduce it into the existing floats. I think.
grad *= (1.0 - 0.042942436724648037 * type) * 3.5946317686139184;
return grad;
}
// BCC lattice split up into 2 cube lattices
vec4 bccNoiseDerivativesPart(vec3 X) {
vec3 b = floor(X);
vec4 i4 = vec4(X - b, 2.5);
// Pick between each pair of oppposite corners in the cube.
vec3 v1 = b + floor(dot(i4, vec4(.25)));
vec3 v2 = b + vec3(1, 0, 0) + vec3(-1, 1, 1) * floor(dot(i4, vec4(-.25, .25, .25, .35)));
vec3 v3 = b + vec3(0, 1, 0) + vec3(1, -1, 1) * floor(dot(i4, vec4(.25, -.25, .25, .35)));
vec3 v4 = b + vec3(0, 0, 1) + vec3(1, 1, -1) * floor(dot(i4, vec4(.25, .25, -.25, .35)));
// Gradient hashes for the four vertices in this half-lattice.
vec4 hashes = permute(mod(vec4(v1.x, v2.x, v3.x, v4.x), 289.0));
hashes = permute(mod(hashes + vec4(v1.y, v2.y, v3.y, v4.y), 289.0));
hashes = mod(permute(mod(hashes + vec4(v1.z, v2.z, v3.z, v4.z), 289.0)), 48.0);
// Gradient extrapolations & kernel function
vec3 d1 = X - v1; vec3 d2 = X - v2; vec3 d3 = X - v3; vec3 d4 = X - v4;
vec4 a = max(0.75 - vec4(dot(d1, d1), dot(d2, d2), dot(d3, d3), dot(d4, d4)), 0.0);
vec4 aa = a * a; vec4 aaaa = aa * aa;
vec3 g1 = grad(hashes.x); vec3 g2 = grad(hashes.y);
vec3 g3 = grad(hashes.z); vec3 g4 = grad(hashes.w);
vec4 extrapolations = vec4(dot(d1, g1), dot(d2, g2), dot(d3, g3), dot(d4, g4));
// Derivatives of the noise
vec3 derivative = -8.0 * mat4x3(d1, d2, d3, d4) * (aa * a * extrapolations)
+ mat4x3(g1, g2, g3, g4) * aaaa;
// Return it all as a vec4
return vec4(derivative, dot(aaaa, extrapolations));
}
// Gives X and Y a triangular alignment, and lets Z move up the main diagonal.
// Might be good for terrain, or a time varying X/Y plane. Z repeats.
vec4 bccNoiseDerivatives_XYBeforeZ(vec3 X) {
// Not a skew transform.
mat3 orthonormalMap = mat3(
0.788675134594813, -0.211324865405187, -0.577350269189626,
-0.211324865405187, 0.788675134594813, -0.577350269189626,
0.577350269189626, 0.577350269189626, 0.577350269189626);
X = orthonormalMap * X;
vec4 result = bccNoiseDerivativesPart(X) + bccNoiseDerivativesPart(X + 144.5);
return vec4(result.xyz * orthonormalMap, result.w);
}
void main()
{
vec2 uv = texUV;
vec2 p = uv;
uv = uv * 2. -1.;
float tickle = 0.001*1000*iTime;
vec3 offset = vec3(cos(tickle), sin(tickle), 0.0);
vec3 p3 = vec3(p, 0.0) + offset;
vec3 noise_input = vec3(p3*25.0+12.0);
//float intensity = noise(noise_input);
float intensity = 0.0;
intensity += bccNoiseDerivatives_XYBeforeZ(noise_input).w*0.4;
intensity += bccNoiseDerivatives_XYBeforeZ(noise_input*0.55).w*0.7;
intensity += bccNoiseDerivatives_XYBeforeZ(noise_input*0.44).w*0.8;
float t = clamp((uv.x * -uv.x * 0.16) + 0.15, 0., 1.);
//fragColor.rgb = vec3(t);
float dist = length(uv);
//float y = abs( dist - 0.5 - intensity * 0.1);
float y = abs(uv.y/1.5 - intensity * 0.1);
float g = pow(y, 0.2);
vec3 col = vec3(2.0, 1.8, 0.5);
col = col * -g + col;
col = col * col;
col = col * col;
fragColor.rgb = col;
fragColor.a = ((col.r + col.g + col.b)/3.0) * alpha;
}
@end
@program program vs fs

@ -38,11 +38,13 @@
// shaders
#include "goodpixel.gen.h"
#include "horizontal_lightning.gen.h"
#include "hueshift.gen.h"
#include "lightning.gen.h"
static sg_pipeline hueshift_pipeline;
static sg_pipeline goodpixel_pipeline;
static sg_pipeline lightning_pipeline;
static sg_pipeline horizontal_lightning_pipeline;
static struct GameState gs = {0};
static int my_player_index = -1;
@ -694,6 +696,20 @@ static void init(void)
quit_with_popup("Couldn't make a shader! Uhhh ooooohhhhhh!!!", "Shader error BONED");
}
}
{
sgp_pipeline_desc pip_desc = {
.shader = *horizontal_lightning_program_shader_desc(sg_query_backend()),
.blend_mode = SGP_BLENDMODE_BLEND,
};
horizontal_lightning_pipeline = sgp_make_pipeline(&pip_desc);
sg_resource_state errstate = sg_query_pipeline_state(horizontal_lightning_pipeline);
if (errstate != SG_RESOURCESTATE_VALID)
{
Log("Failed to make horizontal_lightning pipeline\n");
quit_with_popup("Couldn't make a shader! Uhhh ooooohhhhhh!!!", "Shader error BONED");
}
}
}
// images loading
@ -1839,7 +1855,7 @@ static void frame(void)
{
// "commit" the input. each input must be on a successive tick.
// if (tick(&gs) > last_input_committed_tick)
while(tick(&gs) > last_input_committed_tick)
while (tick(&gs) > last_input_committed_tick)
{
if (replay_inputs_from != NULL)
{
@ -2338,6 +2354,29 @@ static void frame(void)
draw_circle(entity_pos(b), SCANNER_RADIUS * 0.75);
set_color(WHITE);
for (int i = 0; i < SCANNER_MAX_PLATONICS; i++)
if (b->detected_platonics[i].intensity > 0.0)
{
pipeline_scope(horizontal_lightning_pipeline)
{
sgp_set_image(0, (sg_image){0});
horizontal_lightning_uniforms_t uniform = {
.iTime = (float)(iTime + hash11((double)get_id(&gs, b).index)),
.alpha = (float)b->detected_platonics[i].intensity,
};
sgp_set_uniform(&uniform, sizeof(uniform));
transform_scope()
{
cpVect pos = cpvadd(entity_pos(b) , cpvmult(b->detected_platonics[i].direction, SCANNER_RADIUS/2.0));
rotate_at(cpvangle(b->detected_platonics[i].direction), pos.x,pos.y);
draw_color_rect_centered(pos, SCANNER_RADIUS);
}
sgp_reset_image(0);
}
}
set_color(colhexcode(0xf2d75c));
sgp_set_image(0, image_radardot);
for (int i = 0; i < SCANNER_MAX_POINTS; i++)

@ -6,4 +6,5 @@ IF %ERRORLEVEL% NEQ 0 ECHO ERROR download sokol-shdc from https://github.com/flo
@REM example of how to compile shaders: sokol-shdc.exe --input triangle.glsl --output triangle.gen.h --slang glsl330:hlsl5:metal_macos
sokol-shdc.exe --format sokol --input hueshift.glsl --output hueshift.gen.h --slang glsl330:hlsl5:metal_macos
sokol-shdc.exe --format sokol --input lightning.glsl --output lightning.gen.h --slang glsl330:hlsl5:metal_macos
sokol-shdc.exe --format sokol --input horizontal_lightning.glsl --output horizontal_lightning.gen.h --slang glsl330:hlsl5:metal_macos
sokol-shdc.exe --format sokol --input goodpixel.glsl --output goodpixel.gen.h --slang glsl330:hlsl5:metal_macos

@ -71,6 +71,7 @@
#define SCANNER_MAX_VIEWPORT_RANGE 400.0
#define SCANNER_MIN_RANGE 1.0
#define SCANNER_MAX_POINTS 10
#define SCANNER_MAX_PLATONICS 3
#define MAX_SERVER_TO_CLIENT 1024 * 512 // maximum size of serialized gamestate buffer
#define MAX_CLIENT_TO_SERVER 1024 * 10 // maximum size of serialized inputs and mic data
@ -217,7 +218,8 @@ typedef struct EntityID
static inline bool entityids_same(EntityID a, EntityID b)
{
return (a.generation == b.generation) && (a.index == b.index);
return (a.generation == b.generation) && (a.index == b.index);
}
enum ScannerPointKind
@ -251,6 +253,12 @@ typedef struct InputFrame
enum CompassRotation build_rotation;
} InputFrame;
typedef struct PlatonicDetection
{
cpVect direction;
double intensity;
} PlatonicDetection;
typedef struct Entity
{
bool exists;
@ -358,6 +366,8 @@ typedef struct Entity
double scanner_head_rotate_speed; // not serialized, cosmetic
double scanner_head_rotate;
PlatonicDetection detected_platonics[SCANNER_MAX_PLATONICS]; // intensity of 0.0 means undetected
struct ScannerPoint
{
char kind; // is of ScannerPointKind

Loading…
Cancel
Save