add quadtree; add neon to handmademath
This commit is contained in:
@@ -89,7 +89,7 @@ if get_option('enet')
|
||||
endif
|
||||
|
||||
sources = []
|
||||
src += ['anim.c', 'config.c', 'datastream.c','font.c','gameobject.c','HandmadeMath.c','jsffi.c','model.c','render.c','script.c','simplex.c','spline.c', 'timer.c', 'transform.c','warp.c','yugine.c', 'wildmatch.c', 'sprite.c']
|
||||
src += ['anim.c', 'config.c', 'datastream.c','font.c','gameobject.c','HandmadeMath.c','jsffi.c','model.c','render.c','script.c','simplex.c','spline.c', 'timer.c', 'transform.c','warp.c','yugine.c', 'wildmatch.c', 'sprite.c', 'quadtree.c', 'aabb.c']
|
||||
|
||||
imsrc = ['GraphEditor.cpp','ImCurveEdit.cpp','ImGradient.cpp','imgui_draw.cpp','imgui_tables.cpp','imgui_widgets.cpp','imgui.cpp','ImGuizmo.cpp','imnodes.cpp','implot_items.cpp','implot.cpp', 'imgui_impl_sdlrenderer3.cpp', 'imgui_impl_sdl3.cpp', 'imgui_impl_sdlgpu3.cpp']
|
||||
|
||||
|
||||
@@ -21,6 +21,9 @@ frog = {
|
||||
}
|
||||
*/
|
||||
|
||||
var spritetree = os.make_quadtree([0,0], [10000,10000]);
|
||||
globalThis.spritetree = spritetree;
|
||||
|
||||
var sprite = {
|
||||
image: undefined,
|
||||
get diffuse() { return this.image; },
|
||||
@@ -92,6 +95,8 @@ var sprite = {
|
||||
this.sync();
|
||||
this.play();
|
||||
this.transform.scale = [this.image.texture.width, this.image.texture.height];
|
||||
// spritetree.remove(this);
|
||||
|
||||
},
|
||||
stop() {
|
||||
this.del_anim?.();
|
||||
|
||||
@@ -756,9 +756,14 @@ function insertion_sort(arr, cmp)
|
||||
return arr
|
||||
}
|
||||
|
||||
var culled;
|
||||
|
||||
function sprites_to_queue(sprites, ysort = false)
|
||||
{
|
||||
return render._main.make_sprite_queue(allsprites, prosperon.camera, sprite_pipeline)
|
||||
//var culled = spritetree.find(prosperon.camera.pos, prosperon.camera.size);
|
||||
//var culled = spritetree.find(prosperon.camera.transform.pos,prosperon.camera.size)
|
||||
var culled = os.cull_sprites(allsprites,prosperon.camera);
|
||||
return render._main.make_sprite_queue(culled, prosperon.camera, sprite_pipeline)
|
||||
var sprites = allsprites;
|
||||
// for (var i = 0; i < sprites.length; i++)
|
||||
// sprites[i].transform.clean();
|
||||
|
||||
@@ -216,9 +216,11 @@ HMM_Vec4 HMM_AddV4(HMM_Vec4 Left, HMM_Vec4 Right) {
|
||||
|
||||
HMM_Vec4 Result;
|
||||
|
||||
#ifdef HANDMADE_MATH__USE_SSE
|
||||
Result.SSE = _mm_add_ps(Left.SSE, Right.SSE);
|
||||
#else
|
||||
#ifdef HANDMADE_MATH__USE_NEON
|
||||
Result.NEON = vaddq_f32(Left.NEON, Right.NEON);
|
||||
#elif defined(HANDMADE_MATH__USE_SSE)
|
||||
Result.SSE = _mm_add_ps(Left.SSE, Right.SSE);
|
||||
#else
|
||||
Result.X = Left.X + Right.X;
|
||||
Result.Y = Left.Y + Right.Y;
|
||||
Result.Z = Left.Z + Right.Z;
|
||||
@@ -310,9 +312,11 @@ HMM_Vec4 HMM_MulV4(HMM_Vec4 Left, HMM_Vec4 Right) {
|
||||
|
||||
HMM_Vec4 Result;
|
||||
|
||||
#ifdef HANDMADE_MATH__USE_SSE
|
||||
Result.SSE = _mm_mul_ps(Left.SSE, Right.SSE);
|
||||
#else
|
||||
#ifdef HANDMADE_MATH__USE_NEON
|
||||
Result.NEON = vmulq_f32(Left.NEON, Right.NEON);
|
||||
#elif defined(HANDMADE_MATH__USE_SSE)
|
||||
Result.SSE = _mm_mul_ps(Left.SSE, Right.SSE);
|
||||
#else
|
||||
Result.X = Left.X * Right.X;
|
||||
Result.Y = Left.Y * Right.Y;
|
||||
Result.Z = Left.Z * Right.Z;
|
||||
@@ -555,39 +559,63 @@ HMM_Vec4 HMM_LerpV4(HMM_Vec4 A, float Time, HMM_Vec4 B) {
|
||||
/*
|
||||
* SSE stuff
|
||||
*/
|
||||
|
||||
HMM_Vec4 HMM_LinearCombineV4M4_P(HMM_Vec4 *Left, HMM_Mat4 *Right)
|
||||
{
|
||||
HMM_Vec4 Result;
|
||||
|
||||
#ifdef HANDMADE_MATH__USE_NEON
|
||||
float32x4_t a = Left->NEON;
|
||||
|
||||
float x = vgetq_lane_f32(a, 0);
|
||||
float y = vgetq_lane_f32(a, 1);
|
||||
float z = vgetq_lane_f32(a, 2);
|
||||
float w = vgetq_lane_f32(a, 3);
|
||||
|
||||
float32x4_t r0 = vmulq_n_f32(Right->Columns[0].NEON, x);
|
||||
float32x4_t r1 = vmulq_n_f32(Right->Columns[1].NEON, y);
|
||||
float32x4_t r2 = vmulq_n_f32(Right->Columns[2].NEON, z);
|
||||
float32x4_t r3 = vmulq_n_f32(Right->Columns[3].NEON, w);
|
||||
|
||||
float32x4_t sum = vaddq_f32(r0, r1);
|
||||
sum = vaddq_f32(sum, r2);
|
||||
sum = vaddq_f32(sum, r3);
|
||||
|
||||
Result.NEON = sum;
|
||||
#elif defined(HANDMADE_MATH__USE_SSE)
|
||||
Result.SSE = _mm_mul_ps(_mm_shuffle_ps(Left.SSE, Left.SSE, 0x00), Right.Columns[0].SSE);
|
||||
Result.SSE = _mm_add_ps(Result.SSE, _mm_mul_ps(_mm_shuffle_ps(Left.SSE, Left.SSE, 0x55), Right.Columns[1].SSE));
|
||||
Result.SSE = _mm_add_ps(Result.SSE, _mm_mul_ps(_mm_shuffle_ps(Left.SSE, Left.SSE, 0xaa), Right.Columns[2].SSE));
|
||||
Result.SSE = _mm_add_ps(Result.SSE, _mm_mul_ps(_mm_shuffle_ps(Left.SSE, Left.SSE, 0xff), Right.Columns[3].SSE));
|
||||
|
||||
#else
|
||||
Result.X = Left.Elements[0] * Right.Columns[0].X;
|
||||
Result.Y = Left.Elements[0] * Right.Columns[0].Y;
|
||||
Result.Z = Left.Elements[0] * Right.Columns[0].Z;
|
||||
Result.W = Left.Elements[0] * Right.Columns[0].W;
|
||||
|
||||
Result.X += Left.Elements[1] * Right.Columns[1].X;
|
||||
Result.Y += Left.Elements[1] * Right.Columns[1].Y;
|
||||
Result.Z += Left.Elements[1] * Right.Columns[1].Z;
|
||||
Result.W += Left.Elements[1] * Right.Columns[1].W;
|
||||
|
||||
Result.X += Left.Elements[2] * Right.Columns[2].X;
|
||||
Result.Y += Left.Elements[2] * Right.Columns[2].Y;
|
||||
Result.Z += Left.Elements[2] * Right.Columns[2].Z;
|
||||
Result.W += Left.Elements[2] * Right.Columns[2].W;
|
||||
|
||||
Result.X += Left.Elements[3] * Right.Columns[3].X;
|
||||
Result.Y += Left.Elements[3] * Right.Columns[3].Y;
|
||||
Result.Z += Left.Elements[3] * Right.Columns[3].Z;
|
||||
Result.W += Left.Elements[3] * Right.Columns[3].W;
|
||||
#endif
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
HMM_Vec4 HMM_LinearCombineV4M4(HMM_Vec4 Left, HMM_Mat4 Right) {
|
||||
|
||||
HMM_Vec4 Result;
|
||||
#ifdef HANDMADE_MATH__USE_SSE
|
||||
Result.SSE = _mm_mul_ps(_mm_shuffle_ps(Left.SSE, Left.SSE, 0x00), Right.Columns[0].SSE);
|
||||
Result.SSE = _mm_add_ps(Result.SSE, _mm_mul_ps(_mm_shuffle_ps(Left.SSE, Left.SSE, 0x55), Right.Columns[1].SSE));
|
||||
Result.SSE = _mm_add_ps(Result.SSE, _mm_mul_ps(_mm_shuffle_ps(Left.SSE, Left.SSE, 0xaa), Right.Columns[2].SSE));
|
||||
Result.SSE = _mm_add_ps(Result.SSE, _mm_mul_ps(_mm_shuffle_ps(Left.SSE, Left.SSE, 0xff), Right.Columns[3].SSE));
|
||||
#else
|
||||
Result.X = Left.Elements[0] * Right.Columns[0].X;
|
||||
Result.Y = Left.Elements[0] * Right.Columns[0].Y;
|
||||
Result.Z = Left.Elements[0] * Right.Columns[0].Z;
|
||||
Result.W = Left.Elements[0] * Right.Columns[0].W;
|
||||
|
||||
Result.X += Left.Elements[1] * Right.Columns[1].X;
|
||||
Result.Y += Left.Elements[1] * Right.Columns[1].Y;
|
||||
Result.Z += Left.Elements[1] * Right.Columns[1].Z;
|
||||
Result.W += Left.Elements[1] * Right.Columns[1].W;
|
||||
|
||||
Result.X += Left.Elements[2] * Right.Columns[2].X;
|
||||
Result.Y += Left.Elements[2] * Right.Columns[2].Y;
|
||||
Result.Z += Left.Elements[2] * Right.Columns[2].Z;
|
||||
Result.W += Left.Elements[2] * Right.Columns[2].W;
|
||||
|
||||
Result.X += Left.Elements[3] * Right.Columns[3].X;
|
||||
Result.Y += Left.Elements[3] * Right.Columns[3].Y;
|
||||
Result.Z += Left.Elements[3] * Right.Columns[3].Z;
|
||||
Result.W += Left.Elements[3] * Right.Columns[3].W;
|
||||
#endif
|
||||
|
||||
return Result;
|
||||
}
|
||||
return HMM_LinearCombineV4M4_P(&Left, &Right);
|
||||
}
|
||||
|
||||
/*
|
||||
* 2x2 Matrices
|
||||
@@ -1041,6 +1069,17 @@ HMM_Mat4 HMM_MulM4(HMM_Mat4 Left, HMM_Mat4 Right) {
|
||||
return Result;
|
||||
}
|
||||
|
||||
HMM_Mat4 HMM_MulM4_P(HMM_Mat4 *Left, HMM_Mat4 *Right)
|
||||
{
|
||||
HMM_Mat4 Result;
|
||||
Result.Columns[0] = HMM_LinearCombineV4M4_P(&Right->Columns[0], Left);
|
||||
Result.Columns[1] = HMM_LinearCombineV4M4_P(&Right->Columns[1], Left);
|
||||
Result.Columns[2] = HMM_LinearCombineV4M4_P(&Right->Columns[2], Left);
|
||||
Result.Columns[3] = HMM_LinearCombineV4M4_P(&Right->Columns[3], Left);
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
HMM_Mat4 HMM_MulM4F(HMM_Mat4 Matrix, float Scalar) {
|
||||
|
||||
HMM_Mat4 Result;
|
||||
@@ -1073,6 +1112,11 @@ HMM_Mat4 HMM_MulM4F(HMM_Mat4 Matrix, float Scalar) {
|
||||
return Result;
|
||||
}
|
||||
|
||||
HMM_Vec4 HMM_MulM4V4_P(HMM_Mat4 *Matrix, HMM_Vec4 *Vector)
|
||||
{
|
||||
return HMM_LinearCombineV4M4_P(Vector, Matrix);
|
||||
}
|
||||
|
||||
HMM_Vec4 HMM_MulM4V4(HMM_Mat4 Matrix, HMM_Vec4 Vector) {
|
||||
return HMM_LinearCombineV4M4(Vector, Matrix);
|
||||
}
|
||||
|
||||
@@ -98,23 +98,19 @@
|
||||
|
||||
#include <chipmunk/chipmunk.h>
|
||||
|
||||
/* let's figure out if SSE is really available (unless disabled anyway)
|
||||
(it isn't on non-x86/x86_64 platforms or even x86 without explicit SSE support)
|
||||
=> only use "#ifdef HANDMADE_MATH__USE_SSE" to check for SSE support below this block! */
|
||||
#ifndef HANDMADE_MATH_NO_SSE
|
||||
#ifdef _MSC_VER /* MSVC supports SSE in amd64 mode or _M_IX86_FP >= 1 (2 means SSE2) */
|
||||
#if defined(_M_AMD64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 1)
|
||||
#define HANDMADE_MATH__USE_SSE 1
|
||||
#endif
|
||||
#else /* not MSVC, probably GCC, clang, icc or something that doesn't support SSE anyway */
|
||||
#ifdef __SSE__ /* they #define __SSE__ if it's supported */
|
||||
#define HANDMADE_MATH__USE_SSE 1
|
||||
#endif /* __SSE__ */
|
||||
#endif /* not _MSC_VER */
|
||||
#endif /* #ifndef HANDMADE_MATH_NO_SSE */
|
||||
|
||||
#ifdef HANDMADE_MATH__USE_SSE
|
||||
#include <xmmintrin.h>
|
||||
#if !defined(HANDMADE_MATH_NO_SIMD)
|
||||
#if defined(__ARM_NEON) || defined(__ARM_NEON__)
|
||||
#define HANDMADE_MATH__USE_NEON 1
|
||||
#include <arm_neon.h>
|
||||
#elif defined(_MSC_VER)
|
||||
#if defined(_M_AMD64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 1)
|
||||
#define HANDMADE_MATH__USE_SSE 1
|
||||
#include <xmmintrin.h>
|
||||
#endif
|
||||
#elif defined(__SSE__)
|
||||
#define HANDMADE_MATH__USE_SSE 1
|
||||
#include <xmmintrin.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
@@ -390,11 +386,13 @@ typedef union HMM_Vec4 {
|
||||
|
||||
float Elements[4];
|
||||
float e[4];
|
||||
|
||||
|
||||
#ifdef HANDMADE_MATH__USE_SSE
|
||||
__m128 SSE;
|
||||
#endif
|
||||
|
||||
__m128 SSE;
|
||||
#endif
|
||||
#ifdef HANDMADE_MATH__USE_NEON
|
||||
float32x4_t NEON;
|
||||
#endif
|
||||
} HMM_Vec4;
|
||||
|
||||
typedef union HMM_Mat2 {
|
||||
@@ -579,8 +577,10 @@ HMM_Mat4 HMM_TransposeM4(HMM_Mat4 Matrix);
|
||||
HMM_Mat4 HMM_AddM4(HMM_Mat4 Left, HMM_Mat4 Right);
|
||||
HMM_Mat4 HMM_SubM4(HMM_Mat4 Left, HMM_Mat4 Right);
|
||||
HMM_Mat4 HMM_MulM4(HMM_Mat4 Left, HMM_Mat4 Right);
|
||||
HMM_Mat4 HMM_MulM4_P(HMM_Mat4 *Left, HMM_Mat4 *Right);
|
||||
HMM_Mat4 HMM_MulM4F(HMM_Mat4 Matrix, float Scalar);
|
||||
HMM_Vec4 HMM_MulM4V4(HMM_Mat4 Matrix, HMM_Vec4 Vector);
|
||||
HMM_Vec4 HMM_MulM4V4_P(HMM_Mat4 *Matrix, HMM_Vec4 *Vector);
|
||||
HMM_Mat4 HMM_DivM4F(HMM_Mat4 Matrix, float Scalar);
|
||||
float HMM_DeterminantM4(HMM_Mat4 Matrix);
|
||||
|
||||
|
||||
34
source/aabb.c
Normal file
34
source/aabb.c
Normal file
@@ -0,0 +1,34 @@
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "aabb.h"
|
||||
|
||||
aabb*
|
||||
aabb_new(float x, float y, float hW, float hH) {
|
||||
aabb* a = malloc(sizeof(aabb));
|
||||
a->center.x = x;
|
||||
a->center.y = y;
|
||||
a->dims.w = hW;
|
||||
a->dims.h = hH;
|
||||
return a;
|
||||
}
|
||||
|
||||
void
|
||||
aabb_free(aabb *a) {
|
||||
free(a);
|
||||
}
|
||||
|
||||
int
|
||||
aabb_contains(aabb *a, float x, float y) {
|
||||
return (x >= a->center.x-a->dims.w &&
|
||||
x <= a->center.x+a->dims.w) &&
|
||||
(y >= a->center.y-a->dims.h &&
|
||||
y <= a->center.y+a->dims.h);
|
||||
}
|
||||
|
||||
int
|
||||
aabb_intersects(aabb *a, aabb *b) {
|
||||
return (abs(a->center.x - b->center.x) < (a->dims.w + b->dims.w)) &&
|
||||
(abs(a->center.y - b->center.y) < (a->dims.h + b->dims.h));
|
||||
}
|
||||
|
||||
48
source/aabb.h
Normal file
48
source/aabb.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
aabb.h
|
||||
2014 JSK (kutani@projectkutani.com)
|
||||
|
||||
Simple (2D) axis-aligned bounding box implementation. Part of the Panic
|
||||
Panic project.
|
||||
|
||||
Released to the public domain. See LICENSE for details.
|
||||
*/
|
||||
#ifndef _AABB_H
|
||||
#define _AABB_H
|
||||
|
||||
/** \brief axis-aligned bounding box
|
||||
|
||||
Simple struct of four floats, divided into two sub-structs.
|
||||
|
||||
center {x, y} - The center point of the bounding box
|
||||
dims {w, h} - The half-width and half-height of the box
|
||||
*/
|
||||
typedef struct aabb {
|
||||
struct {
|
||||
float x;
|
||||
float y;
|
||||
} center;
|
||||
struct {
|
||||
float w;
|
||||
float h;
|
||||
} dims;
|
||||
} aabb;
|
||||
|
||||
/// Malloc's a new aabb struct
|
||||
/*!
|
||||
Mallocs a new aabb struct and sets center and dims to the passed
|
||||
x, y, hW, and hH values.
|
||||
*/
|
||||
aabb* aabb_new(float x, float y, float hW, float hH);
|
||||
|
||||
|
||||
/// Frees the passed aabb.
|
||||
void aabb_free(aabb *a);
|
||||
|
||||
/// Checks if the point x,y lies within the passed aabb
|
||||
int aabb_contains(aabb *a, float x, float y);
|
||||
|
||||
/// Checks if the two passed aabb's intersect
|
||||
int aabb_intersects(aabb *a, aabb *b);
|
||||
|
||||
#endif
|
||||
119
source/jsffi.c
119
source/jsffi.c
@@ -31,6 +31,8 @@
|
||||
|
||||
#include "sprite.h"
|
||||
|
||||
#include "quadtree.h"
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
#include <SDL3/SDL_gpu.h>
|
||||
#include <SDL3/SDL_error.h>
|
||||
@@ -131,6 +133,7 @@ static JSAtom clamp_border_atom;
|
||||
static JSAtom vertex_atom;
|
||||
static JSAtom index_atom;
|
||||
static JSAtom indirect_atom;
|
||||
static JSAtom rect_atom;
|
||||
|
||||
typedef struct texture_vertex {
|
||||
float x, y, z;
|
||||
@@ -1147,7 +1150,12 @@ QJSCLASS(SDL_GPUCopyPass)
|
||||
QJSCLASS(SDL_GPURenderPass)
|
||||
QJSCLASS(SDL_Cursor)
|
||||
|
||||
void qtree_free(JSRuntime *rt, qtree *tree)
|
||||
{
|
||||
qtree_destroy(*tree);
|
||||
}
|
||||
|
||||
QJSCLASS(qtree)
|
||||
|
||||
int js_arrlen(JSContext *js,JSValue v) {
|
||||
if (JS_IsUndefined(v)) return 0;
|
||||
@@ -3400,6 +3408,7 @@ JSC_CCALL(renderer_make_sprite_mesh,
|
||||
{0.0,1.0,1.0},
|
||||
{1.0,1.0,1.0}
|
||||
};
|
||||
|
||||
for (int j = 0; j < 4; j++)
|
||||
posdata[base+j] = HMM_MulM3V3(trmat, base_quad[j]).xy;
|
||||
|
||||
@@ -3999,7 +4008,13 @@ static HMM_Vec3 base_quad[4] = {
|
||||
{0.0,1.0,1.0},
|
||||
{1.0,1.0,1.0}
|
||||
};
|
||||
|
||||
static HMM_Vec4 base_quad_4[4] = {
|
||||
{ 0.0,0.0, 1.0f, 1.0f },
|
||||
{ 1,0,0.0, 1.0f, 1.0f },
|
||||
{ 0.0,1.0, 1.0f, 1.0f },
|
||||
{ 1.0,1.0, 1.0f, 1.0f }
|
||||
};
|
||||
|
||||
static inline void add_quad(text_vert **verts, rect *restrict src, rect *restrict dst)
|
||||
{
|
||||
text_vert v = (text_vert){
|
||||
@@ -4079,12 +4094,13 @@ JSC_CCALL(gpu_sort_sprite,
|
||||
return number2js(js,0);
|
||||
)
|
||||
|
||||
inline int sprite_in_view(HMM_Mat3 sprite, HMM_Mat4 camera)
|
||||
inline int sprite_in_view(HMM_Mat4 sprite, HMM_Mat4 camera)
|
||||
{
|
||||
HMM_Mat4 camsprite = HMM_MulM4(camera, sprite);
|
||||
int outside = 0;
|
||||
for (int j = 0; j < 4; j++) {
|
||||
HMM_Vec3 corner = HMM_MulM3V3(sprite, (HMM_Vec3){base_quad[j].x, base_quad[j].y, 1.0});
|
||||
HMM_Vec4 clip = HMM_MulM4V4(camera, (HMM_Vec4){corner.x,corner.y,corner.z,1.0});
|
||||
HMM_Vec4 clip = HMM_MulM4V4_P(&camsprite, &base_quad_4[j]);
|
||||
|
||||
if (clip.w <= 0.0) {
|
||||
outside++;
|
||||
continue;
|
||||
@@ -4114,12 +4130,8 @@ JSC_CCALL(gpu_make_sprite_queue,
|
||||
JSValue sub = JS_GetPropertyUint32(js, argv[0], i);
|
||||
transform *t;
|
||||
JS_GETATOM(js,t,sub,transform_atom,transform)
|
||||
HMM_Mat3 trmat = transform2mat3_global(t);
|
||||
if (!sprite_in_view(trmat,info.world_to_projection)) {
|
||||
JS_FreeValue(js,sub);
|
||||
continue;
|
||||
}
|
||||
|
||||
HMM_Mat4 trmat = transform2mat4_global(t);
|
||||
|
||||
rect src;
|
||||
HMM_Vec4 color;
|
||||
|
||||
@@ -4129,7 +4141,7 @@ JSC_CCALL(gpu_make_sprite_queue,
|
||||
quad sprite_quad;
|
||||
|
||||
for (int j = 0; j < 4; j++)
|
||||
sprite_quad.vert[j].pos = HMM_MulM3V3(trmat, base_quad[j]).xy;
|
||||
sprite_quad.vert[j].pos = HMM_MulM4V4_P(&trmat, &(HMM_Vec4){base_quad[j].x,base_quad[j].y,1.0,1.0}).xy;
|
||||
|
||||
sprite_quad.vert[0].uv = (HMM_Vec2){ src.x, src.y + src.h };
|
||||
sprite_quad.vert[1].uv = (HMM_Vec2){ src.x+src.w, src.y + src.h };
|
||||
@@ -4150,7 +4162,7 @@ JSC_CCALL(gpu_make_sprite_queue,
|
||||
|
||||
JS_FreeValue(js, sub);
|
||||
}
|
||||
|
||||
|
||||
qsort(sprites, arrlen(sprites),sizeof(sprite),sort_sprite);
|
||||
|
||||
text_vert *buffer = NULL;
|
||||
@@ -4185,6 +4197,17 @@ JSC_CCALL(gpu_make_sprite_queue,
|
||||
} else count++;
|
||||
JS_FreeValue(js,sprites[i].image);
|
||||
}
|
||||
|
||||
if (count > 0) {
|
||||
JSValue q = JS_NewObject(js);
|
||||
JS_SetPropertyStr(js,q,"type", JS_NewString(js,"geometry"));
|
||||
JS_SetPropertyStr(js,q,"mesh", JS_DupValue(js,mesh));
|
||||
JS_SetPropertyStr(js,q,"pipeline", JS_DupValue(js,argv[2]));
|
||||
JS_SetPropertyStr(js,q,"image", JS_DupValue(js,img));
|
||||
JS_SetPropertyStr(js,q,"first_index", number2js(js,first_index));
|
||||
JS_SetPropertyStr(js,q,"num_indices",number2js(js,count*6));
|
||||
JS_SetPropertyUint32(js,ret,n++,q);
|
||||
}
|
||||
|
||||
arrfree(sprites);
|
||||
JS_FreeValue(js,mesh);
|
||||
@@ -5933,6 +5956,17 @@ JSC_CCALL(transform_dirty,
|
||||
return JS_NewBool(js,transform_dirty_chain(js2transform(js,self)));
|
||||
)
|
||||
|
||||
JSC_CCALL(transform_torect,
|
||||
transform *t = js2transform(js,self);
|
||||
HMM_Mat4 m3 = transform2mat4_global(t);
|
||||
rect r = {0};
|
||||
r.x = m3.Columns[3].x;
|
||||
r.y = m3.Columns[3].y;
|
||||
r.w = m3.Columns[0].x;
|
||||
r.h = m3.Columns[1].y;
|
||||
return rect2js(js,r);
|
||||
)
|
||||
|
||||
static const JSCFunctionListEntry js_transform_funcs[] = {
|
||||
CGETSET_ADD(transform, pos),
|
||||
CGETSET_ADD(transform, scale),
|
||||
@@ -5950,6 +5984,7 @@ static const JSCFunctionListEntry js_transform_funcs[] = {
|
||||
MIST_FUNC_DEF(transform, array, 0),
|
||||
MIST_FUNC_DEF(transform, clean, 0),
|
||||
MIST_FUNC_DEF(transform, dirty, 0),
|
||||
MIST_FUNC_DEF(transform, torect, 0),
|
||||
};
|
||||
|
||||
JSC_CCALL(datastream_time, return number2js(js,plm_get_time(js2datastream(js,self)->plm)); )
|
||||
@@ -7026,7 +7061,7 @@ JSC_CCALL(os_cull_sprites,
|
||||
JSValue sub = JS_GetPropertyUint32(js,sprites, i);
|
||||
transform *t;
|
||||
JS_GETATOM(js,t,sub,transform_atom,transform)
|
||||
HMM_Mat3 trmat = t->gcache3;
|
||||
HMM_Mat4 trmat = transform2mat4_global(t);
|
||||
if (sprite_in_view(trmat, info.world_to_projection)) {
|
||||
JS_SetPropertyUint32(js,ret,n,JS_DupValue(js,sub));
|
||||
n++;
|
||||
@@ -7035,6 +7070,26 @@ JSC_CCALL(os_cull_sprites,
|
||||
}
|
||||
)
|
||||
|
||||
static JSContext *global_js;
|
||||
|
||||
int js_qtree_cmp(JSValue *v, aabb *range)
|
||||
{
|
||||
rect rect;
|
||||
JSValue val = *v;
|
||||
JS_GETATOM(global_js,rect,val,rect_atom,rect)
|
||||
return (rect.x + rect.w < range->center.x+range->dims.w
|
||||
&& rect.x > range->center.x-range->dims.w
|
||||
&& rect.y > range->center.y-range->dims.h
|
||||
&& rect.y + rect.h < range->center.y + range->dims.h);
|
||||
}
|
||||
|
||||
JSC_CCALL(os_make_quadtree,
|
||||
HMM_Vec2 center = js2vec2(js,argv[0]);
|
||||
HMM_Vec2 wh = js2vec2(js,argv[1]);
|
||||
qtree tree = qtree_new(center.x,center.y,wh.x,wh.y, js_qtree_cmp);
|
||||
return qtree2js(js,tree);
|
||||
)
|
||||
|
||||
static const JSCFunctionListEntry js_os_funcs[] = {
|
||||
MIST_FUNC_DEF(os, turbulence, 4),
|
||||
MIST_FUNC_DEF(os, model_buffer, 1),
|
||||
@@ -7051,6 +7106,7 @@ static const JSCFunctionListEntry js_os_funcs[] = {
|
||||
MIST_FUNC_DEF(os, exit, 1),
|
||||
MIST_FUNC_DEF(os, gc, 0),
|
||||
MIST_FUNC_DEF(os, eval, 2),
|
||||
MIST_FUNC_DEF(os, make_quadtree, 2),
|
||||
MIST_FUNC_DEF(os, make_texture, 1),
|
||||
MIST_FUNC_DEF(os, make_gif, 1),
|
||||
MIST_FUNC_DEF(os, make_aseprite, 1),
|
||||
@@ -7099,7 +7155,41 @@ static const JSCFunctionListEntry js_os_funcs[] = {
|
||||
MIST_FUNC_DEF(os, cull_sprites, 2),
|
||||
};
|
||||
|
||||
JSC_CCALL(qtree_insert,
|
||||
qtree tree = js2qtree(js,self);
|
||||
JSValue *item = malloc(sizeof(*item));
|
||||
*item = JS_DupValue(js,argv[0]);
|
||||
qtree_insert(tree, item);
|
||||
)
|
||||
|
||||
JSC_CCALL(qtree_remove,
|
||||
qtree tree = js2qtree(js,self);
|
||||
JSValue item = argv[0];
|
||||
)
|
||||
|
||||
JSC_CCALL(qtree_find,
|
||||
qtree tree = js2qtree(js,self);
|
||||
HMM_Vec2 c = js2vec2(js,argv[0]);
|
||||
HMM_Vec2 wh = js2vec2(js,argv[1]);
|
||||
c.x -= wh.x/2.0;
|
||||
c.y -= wh.y/2.0;
|
||||
uint32_t n;
|
||||
JSValue **items = qtree_findInArea(tree, c.x, c.y, wh.x, wh.y, &n);
|
||||
|
||||
ret = JS_NewArray(js);
|
||||
if (n > 0)
|
||||
JS_SetPropertyUint32(js,ret,0,JS_DupValue(js,*items[0]));
|
||||
|
||||
/*
|
||||
for (int i = 0; i < n; i++)
|
||||
JS_SetPropertyUint32(js,ret,i, JS_DupValue(js,*items[i]));*/
|
||||
)
|
||||
|
||||
static const JSCFunctionListEntry js_qtree_funcs[] = {
|
||||
MIST_FUNC_DEF(qtree, insert, 1),
|
||||
MIST_FUNC_DEF(qtree, remove, 1),
|
||||
MIST_FUNC_DEF(qtree, find, 2),
|
||||
};
|
||||
|
||||
static const JSCFunctionListEntry js_jssprite_funcs[] = {
|
||||
};
|
||||
@@ -7161,6 +7251,7 @@ void ffi_load(JSContext *js) {
|
||||
|
||||
JSValue globalThis = JS_GetGlobalObject(js);
|
||||
|
||||
QJSCLASSPREP_FUNCS(qtree)
|
||||
QJSCLASSPREP_FUNCS(SDL_Window)
|
||||
QJSCLASSPREP_FUNCS(SDL_Surface)
|
||||
QJSCLASSPREP_FUNCS(SDL_Thread)
|
||||
@@ -7312,8 +7403,10 @@ void ffi_load(JSContext *js) {
|
||||
indirect_atom = JS_NewAtom(js, "indirect");
|
||||
num_indices_atom = JS_NewAtom(js,"num_indices");
|
||||
parent_atom = JS_NewAtom(js,"parent");
|
||||
rect_atom = JS_NewAtom(js,"rect");
|
||||
|
||||
fill_event_atoms(js);
|
||||
global_js = js;
|
||||
|
||||
JS_FreeValue(js,globalThis);
|
||||
}
|
||||
|
||||
276
source/quadtree.c
Normal file
276
source/quadtree.c
Normal file
@@ -0,0 +1,276 @@
|
||||
/*
|
||||
quadtree.c
|
||||
2014 JSK (kutani@projectkutani.com)
|
||||
|
||||
Part of the Panic Panic project.
|
||||
|
||||
Released to the public domain. See LICENSE for details.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "aabb.h"
|
||||
|
||||
/// Default node size cap
|
||||
#define QTREE_STDCAP 4
|
||||
|
||||
/// A function pointer def for determining if an element exists in a range
|
||||
typedef int (*qtree_fnc)(void *ptr, aabb *range);
|
||||
|
||||
/// Quadtree node
|
||||
typedef struct qnode {
|
||||
uint16_t cnt; ///< Number of elements in this node
|
||||
aabb bound; ///< Area this node covers
|
||||
void **elist; ///< List of element pointers
|
||||
struct qnode *nw; ///< NW quadrant of this node
|
||||
struct qnode *ne; ///< NE quadrant of this node
|
||||
struct qnode *sw; ///< SW quadrant of this node
|
||||
struct qnode *se; ///< SE quadrant of this node
|
||||
} qnode;
|
||||
|
||||
/// Quadtree container
|
||||
typedef struct _qtree {
|
||||
uint16_t maxnodecap; ///< Maximum element count per node
|
||||
qnode *root; ///< Root node
|
||||
qtree_fnc cmpfnc; ///< Element range compare function pointer
|
||||
} _qtree;
|
||||
|
||||
typedef struct _qtree* qtree;
|
||||
|
||||
/// Simple container for returning found elements
|
||||
typedef struct retlist {
|
||||
uint32_t cnt; ///< Number of elements found
|
||||
aabb range; ///< Range to use for searching
|
||||
void **list; ///< Array of pointers to found elements
|
||||
} retlist;
|
||||
|
||||
static void
|
||||
retlist_add(retlist *r, void *p) {
|
||||
r->list = realloc(r->list, sizeof(void*)*(r->cnt+1));
|
||||
r->list[r->cnt] = p;
|
||||
r->cnt++;
|
||||
}
|
||||
|
||||
static uint16_t
|
||||
qtree_getMaxNodeCnt(qtree q) {
|
||||
uint16_t r;
|
||||
r = q->maxnodecap;
|
||||
return r;
|
||||
}
|
||||
|
||||
static qnode*
|
||||
qnode_new(qtree p, float x, float y, float hW, float hH) {
|
||||
qnode *q = malloc(sizeof(qnode));
|
||||
memset(q, 0, sizeof(qnode));
|
||||
q->bound.center.x = x;
|
||||
q->bound.center.y = y;
|
||||
q->bound.dims.w = hW;
|
||||
q->bound.dims.h = hH;
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
static void
|
||||
qnode_free(qtree q, qnode *qn) {
|
||||
|
||||
if(qn->cnt)
|
||||
free(qn->elist);
|
||||
|
||||
qn->cnt = 0;
|
||||
|
||||
if(qn->nw) {
|
||||
qnode_free(q, qn->nw);
|
||||
qnode_free(q, qn->ne);
|
||||
qnode_free(q, qn->sw);
|
||||
qnode_free(q, qn->se);
|
||||
}
|
||||
|
||||
free(qn);
|
||||
}
|
||||
|
||||
static void
|
||||
add(qnode *q, void *p) {
|
||||
q->elist = realloc(q->elist, sizeof(void*)*(q->cnt+1));
|
||||
q->elist[q->cnt] = p;
|
||||
q->cnt++;
|
||||
}
|
||||
|
||||
static void
|
||||
drop(qnode *q, uint16_t idx) {
|
||||
void **narry = malloc(sizeof(void*)*(q->cnt-1));
|
||||
|
||||
// This is a little (lot) ugly; a pair of memcpy's would be
|
||||
// better, but I had some problems with it
|
||||
for(uint16_t i=0,skip=0; i<q->cnt; i++) {
|
||||
if(i == idx) { skip++; continue; }
|
||||
narry[i-skip] = q->elist[i];
|
||||
}
|
||||
|
||||
void **old = q->elist;
|
||||
q->elist = narry;
|
||||
free(old);
|
||||
q->cnt--;
|
||||
}
|
||||
|
||||
static void
|
||||
subdivide(qtree p, qnode *q) {
|
||||
float cx = q->bound.center.x;
|
||||
float cy = q->bound.center.y;
|
||||
float hw = q->bound.dims.w/2;
|
||||
float hh = q->bound.dims.h/2;
|
||||
|
||||
q->nw = qnode_new(p, cx-hw, cy-hh, hw, hh);
|
||||
q->ne = qnode_new(p, cx+hw, cy-hh, hw, hh);
|
||||
q->sw = qnode_new(p, cx-hw, cy+hh, hw, hh);
|
||||
q->se = qnode_new(p, cx+hw, cy+hh, hw, hh);
|
||||
}
|
||||
|
||||
static int
|
||||
qnode_insert(qtree q, qnode *qn, void *ptr) {
|
||||
int ret = 0;
|
||||
|
||||
if(! (q->cmpfnc)(ptr, &qn->bound))
|
||||
goto QN_INS_EXIT;
|
||||
|
||||
if(qn->cnt < qtree_getMaxNodeCnt(q)) {
|
||||
add(qn, ptr);
|
||||
ret = 1;
|
||||
goto QN_INS_EXIT;
|
||||
}
|
||||
|
||||
if(! qn->nw)
|
||||
subdivide(q, qn);
|
||||
|
||||
if(qnode_insert(q,qn->nw,ptr))
|
||||
return 1;
|
||||
else if(qnode_insert(q,qn->ne,ptr))
|
||||
return 1;
|
||||
else if(qnode_insert(q,qn->sw,ptr))
|
||||
return 1;
|
||||
else if(qnode_insert(q,qn->se,ptr))
|
||||
return 1;
|
||||
|
||||
QN_INS_EXIT:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void*
|
||||
qnode_remove(qtree q, qnode *qn, void *ptr) {
|
||||
if(qn->cnt) {
|
||||
for(uint16_t i=0; i<qn->cnt; i++) {
|
||||
if(qn->elist[i] == ptr) {
|
||||
drop(qn, i);
|
||||
ptr = NULL;
|
||||
goto QN_REM_EXIT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(! qn->nw)
|
||||
return NULL;
|
||||
|
||||
if(qnode_remove(q, qn->nw, ptr)) return ptr;
|
||||
if(qnode_remove(q, qn->ne, ptr)) return ptr;
|
||||
if(qnode_remove(q, qn->sw, ptr)) return ptr;
|
||||
if(qnode_remove(q, qn->se, ptr)) return ptr;
|
||||
|
||||
return NULL;
|
||||
QN_REM_EXIT:
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static void
|
||||
qnode_getInRange(qtree q, qnode *qn, retlist *r) {
|
||||
if(qn->cnt) {
|
||||
if(! aabb_intersects(&qn->bound, &r->range))
|
||||
goto QN_GET_EXIT;
|
||||
|
||||
for(uint16_t i=0; i<qn->cnt; i++)
|
||||
if((q->cmpfnc)(qn->elist[i], &r->range))
|
||||
retlist_add(r, qn->elist[i]);
|
||||
}
|
||||
|
||||
if(! qn->nw)
|
||||
goto QN_GET_EXIT;
|
||||
|
||||
qnode_getInRange(q, qn->nw, r);
|
||||
qnode_getInRange(q, qn->ne, r);
|
||||
qnode_getInRange(q, qn->sw, r);
|
||||
qnode_getInRange(q, qn->se, r);
|
||||
|
||||
QN_GET_EXIT:
|
||||
return;
|
||||
}
|
||||
|
||||
/* exports */
|
||||
|
||||
qtree
|
||||
qtree_new(float x, float y, float w, float h, qtree_fnc fnc) {
|
||||
qtree q = malloc(sizeof(_qtree));
|
||||
memset(q, 0, sizeof(_qtree));
|
||||
|
||||
q->maxnodecap = QTREE_STDCAP;
|
||||
q->cmpfnc = fnc;
|
||||
q->root = qnode_new(q, x+(w/2),y+(h/2),w/2,h/2);
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
void
|
||||
qtree_destroy(qtree q) {
|
||||
void *m;
|
||||
if(q->root) qnode_free(q, q->root);
|
||||
|
||||
memset(q, 0, sizeof(_qtree));
|
||||
|
||||
free(q);
|
||||
}
|
||||
|
||||
void
|
||||
qtree_insert(qtree q, void *ptr) {
|
||||
qnode_insert(q, q->root, ptr);
|
||||
}
|
||||
|
||||
void
|
||||
qtree_remove(qtree q, void *ptr) {
|
||||
qnode_remove(q, q->root, ptr);
|
||||
}
|
||||
|
||||
void
|
||||
qtree_setMaxNodeCnt(qtree q, uint16_t cnt) {
|
||||
q->maxnodecap = cnt || 1;
|
||||
}
|
||||
|
||||
void
|
||||
qtree_clear(qtree q) {
|
||||
float x = q->root->bound.center.x;
|
||||
float y = q->root->bound.center.y;
|
||||
float w = q->root->bound.dims.w;
|
||||
float h = q->root->bound.dims.h;
|
||||
qnode *qn = q->root;
|
||||
|
||||
q->root = qnode_new(q, x, y, w, h);
|
||||
|
||||
qnode_free(q, qn);
|
||||
}
|
||||
|
||||
void**
|
||||
qtree_findInArea(qtree q, float x, float y, float w, float h, uint32_t *cnt) {
|
||||
float hw = w/2;
|
||||
float hh = h/2;
|
||||
|
||||
retlist ret;
|
||||
memset(&ret, 0, sizeof(retlist));
|
||||
|
||||
ret.range.center.x = x+hw;
|
||||
ret.range.center.y = y+hh;
|
||||
ret.range.dims.w = hw;
|
||||
ret.range.dims.h = hh;
|
||||
|
||||
qnode_getInRange(q, q->root, &ret);
|
||||
|
||||
*cnt = ret.cnt;
|
||||
return ret.list;
|
||||
}
|
||||
76
source/quadtree.h
Normal file
76
source/quadtree.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
quadtree.h
|
||||
2014 JSK (kutani@projectkutani.com)
|
||||
|
||||
Part of the Panic Panic project.
|
||||
|
||||
Released to the public domain. See LICENSE for details.
|
||||
*/
|
||||
#ifndef _QUADTREE_H
|
||||
#define _QUADTREE_H
|
||||
|
||||
#ifndef _AABB_H
|
||||
#include "aabb.h"
|
||||
#endif
|
||||
|
||||
/// Opaque pointer to a quadtree data structure
|
||||
typedef struct _qtree* qtree;
|
||||
|
||||
/// A function pointer def for determining if an element exists in a range
|
||||
typedef int (*qtree_fnc)(void *ptr, aabb *range);
|
||||
|
||||
/// Create a new qtree
|
||||
/*!
|
||||
Creates a new qtree with a bound of w,h size, centered at x,y.
|
||||
|
||||
Uses the passed function pointer fnc to test elements against nodes
|
||||
for insertion, and finding.
|
||||
|
||||
Returns a new qtree pointer.
|
||||
*/
|
||||
qtree qtree_new(float x, float y, float w, float h, qtree_fnc fnc);
|
||||
|
||||
void qtree_destroy(qtree q);
|
||||
|
||||
/// Insert an element
|
||||
/*!
|
||||
Inserts the passed element into quadtree q.
|
||||
|
||||
Uses the function passed to qtree_new() to determine where the
|
||||
element should go.
|
||||
*/
|
||||
void qtree_insert(qtree q, void *ptr);
|
||||
|
||||
/// Removes an element from the quadtree
|
||||
/*!
|
||||
Performs a selective removal of the passed element.
|
||||
|
||||
Performs a naive pointer comparison and a depth-first search of the
|
||||
tree, so this isn't very fast.
|
||||
*/
|
||||
void qtree_remove(qtree q, void *ptr);
|
||||
|
||||
/// Set the maximum number of elements per node
|
||||
/*!
|
||||
Sets the maximum elements per quadtree node.
|
||||
|
||||
The default is 4.
|
||||
*/
|
||||
void qtree_setMaxNodeCnt(qtree q, uint16_t cnt);
|
||||
|
||||
/// Resets a quadtree
|
||||
/*!
|
||||
Clears all nodes held by the quadtree and creates a fresh root node
|
||||
with no elements assigned.
|
||||
*/
|
||||
void qtree_clear(qtree q);
|
||||
|
||||
/// Find all elements within a rectangular bound
|
||||
/*!
|
||||
Performs a search for any elements within the given x,y + w,h
|
||||
bound. Returns an array of pointers to any elements (which should be
|
||||
freed by the user), and places the number of elements in cnt.
|
||||
*/
|
||||
void** qtree_findInArea(qtree q, float x, float y, float w, float h, uint32_t *cnt);
|
||||
|
||||
#endif
|
||||
@@ -72,14 +72,27 @@ HMM_Mat3 transform2mat3(transform *t)
|
||||
return t->cache3;
|
||||
}
|
||||
|
||||
HMM_Mat4 transform2mat4_global(transform *t)
|
||||
{
|
||||
if (!transform_dirty_chain(t)) return t->gcache;
|
||||
|
||||
HMM_Mat4 tm = transform2mat(t);
|
||||
if (t->parent)
|
||||
t->gcache = HMM_MulM4(transform2mat(t->parent), tm);
|
||||
else
|
||||
t->gcache = tm;
|
||||
|
||||
return t->gcache;
|
||||
}
|
||||
|
||||
HMM_Mat3 transform2mat3_global(transform *t)
|
||||
{
|
||||
if (!transform_dirty_chain(t)) return t->gcache3;
|
||||
|
||||
HMM_Mat3 tm = transform2mat3(t);
|
||||
if (t->parent) {
|
||||
if (t->parent)
|
||||
t->gcache3 = HMM_MulM3(transform2mat3(t->parent), tm);
|
||||
} else
|
||||
else
|
||||
t->gcache3 = tm;
|
||||
|
||||
return t->gcache3;
|
||||
|
||||
@@ -48,6 +48,7 @@ HMM_Vec3 mat3_t_dir(HMM_Mat4 m, HMM_Vec3 dir);
|
||||
HMM_Mat4 transform2mat(transform *t);
|
||||
HMM_Mat3 transform2mat3(transform *t);
|
||||
|
||||
HMM_Mat4 transform2mat4_global(transform *t);
|
||||
HMM_Mat3 transform2mat3_global(transform *t);
|
||||
int transform_dirty_chain(transform *t);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user