diff --git a/.cell/cell.toml b/.cell/cell.toml new file mode 100644 index 00000000..bdf5a849 --- /dev/null +++ b/.cell/cell.toml @@ -0,0 +1,2 @@ +[compilation] +LDFLAGS = "-lSDL3" diff --git a/3pfollow.h b/3pfollow.h deleted file mode 100644 index 1ca697eb..00000000 --- a/3pfollow.h +++ /dev/null @@ -1,168 +0,0 @@ -#ifndef THIRDPERSONFOLLOW_H -#define THIRDPERSONFOLLOW_H - -#include "transform.h" -#include "HandmadeMath.h" - -/* - -class ThirdPersonFollow { - - public: - enum CameraType { - STATIONARY, - TRANSLATING, - ROTATING, - SPLINE - }; - - enum CameraTransition { - NONE, - CROSSDISSOLVE, - WIPE, - DIP - }; - - enum FrameOfReference { - LOCAL, - WORLD, - EXTERNAL - }; - - ThirdPersonFollow() { - // Rotation - RotationSpeed = 10.0f; - LockPitch = LockYaw = LockRoll = true; - - XDirPosts = false; - YDirPosts = false; - ZDirPosts = false; - - - // Translation - //FloatWidths = AnchorWidths = CenterVector = glm::vec3(0, 0, 0); - PositionSpeeds = glm::vec3(2.f, 2.f, 2.f); - //TranslationScales = glm::vec3(1, 1, 1); - - // Frame settings - Offset = glm::vec3(0.f, 0.f, 0.f); - Distance = 10; - - AnchorSpeed = 80; - } ~ThirdPersonFollow() { - } - - Transform *mytransform; - - // An actor that can be given for the camera to base its movement around - // instead of itself. Makes most sense for this to be stationary - Transform *ExternalFrame = nullptr; - - - void SetExternalFrame(Transform * val) { - ExternalFrame = val; - } - - // The target the camera "looks" at, used for calculations - Transform *Target = nullptr; - - void SetTarget(Transform * val) { - Target = val; - } - - // Offset from the target - glm::vec3 Offset; - - // How far away should the camera act from the target - float Distance; - - /////////////////////////////////////////////////////////////////////////// - // Translation variables. In this mode, the camera doesn't rotate to look - // at the target, it only moves around the world. - /////////////////////////////////////////////////////////////////////////// - - /// "Posts" for each direction in 3D space. These are items that the target - /// is allowed to move within without the camera following along. - bool XDirPosts; - bool YDirPosts; - bool ZDirPosts; - - /// The range in ecah direction the camera floats. While within this range, - /// the camera will smoothly glide to the desired position. - glm::vec3 FloatWidths; - - /// The clamp range for each direction. If the camera reaches this range, - /// it will stick and not move any further. - glm::vec3 AnchorWidths; - - /// When floating to the target, the speed to float. - glm::vec3 PositionSpeeds; - - ////////////////////////////////////////////////////////////////////////// - // Rotation variables. Used for the camera's rotation mode, where it - // follows the Target without translating. - ////////////////////////////////////////////////////////////////////////// - - /// Variables to lock its rotation in any of the three directions - bool LockRoll; - bool LockPitch; - bool LockYaw; - - glm::vec3 RotationOffset; - - /// The speed of rotation - float RotationSpeed; - - private: - void CalculateTargetOffset(); - - // Transform of frame of reference - Transform TFOR; - - /// The calculated offset based on frames of reference - glm::vec3 TargetOffset; - - glm::vec3 TargetPosition; - - glm::quat TargetRotation; - - - void CalculateTargets(); - - // Calculates - - glm::vec3 CalculatePosition(); - - glm::vec3 CalculateCenter(); - - /// Given a direction and width, find the offsets. - glm::vec3 GetPostsOffset(const glm::vec3 & DirectionVector, - float AnchorWidth); - - /// Given anchors, what's the anchor width? - glm::vec3 GetExtentsOffset(const glm::vec3 & DirectionVector, - float AnchorWidth, float TOffset, - float Width); - - glm::quat RemoveLockedRotation(const glm::quat & CurrentRotation); - - glm::vec3 FrameBasedVectorLerp(const glm::vec3 & From, - const glm::vec3 & To, - const glm::vec3 & Speeds, float Tick); - - glm::vec3 VectorLerpPiecewise(const glm::vec3 & From, - const glm::vec3 & To, - const glm::vec3 & Alpha); - - bool GetLerpParam(const float Offst, const float AnchorWidth, - const float FloatWidth); - - /// Set to a value that gives good clamping, smoothly. Activates when - /// the target is out of range. - float AnchorSpeed; - -}; - -*/ - -#endif diff --git a/3pfollow.c b/3pfollow.md similarity index 98% rename from 3pfollow.c rename to 3pfollow.md index 36abef39..90850f64 100644 --- a/3pfollow.c +++ b/3pfollow.md @@ -1,5 +1,4 @@ -#include "3pfollow.h" -#include +This was a good camera system for third person games. Recreate it eventually in cell. // void ThirdPersonFollow::_ready() { // Target = dynamic_cast(get_node(TargetPath)); diff --git a/anim.c b/anim.c deleted file mode 100644 index 5c106094..00000000 --- a/anim.c +++ /dev/null @@ -1,63 +0,0 @@ -#include "anim.h" -#include "stb_ds.h" - -void animation_run(struct animation *anim, float now) -{ - float elapsed = now - anim->time; - elapsed = fmod(elapsed,2); - if (!anim->channels) return; - - for (int i = 0; i < arrlen(anim->channels); i++) { - struct anim_channel *ch = anim->channels+i; - HMM_Vec4 s = sample_sampler(ch->sampler, elapsed); - *(ch->target) = s; - } -} - -HMM_Vec4 sample_cubicspline(sampler *sampler, float t, int prev, int next) -{ - HMM_Vec4 ret; - HMM_Quat qv = HMM_SLerp(HMM_QV4(sampler->data[prev]), t, HMM_QV4(sampler->data[next])); - memcpy(ret.e, qv.e, sizeof(ret.e)); - return ret; -} - -HMM_Vec4 sample_sampler(sampler *sampler, float time) -{ - if (arrlen(sampler->data) == 0) return v4zero; - if (arrlen(sampler->data) == 1) return sampler->data[0]; - int previous_time=0; - int next_time=0; - - for (int i = 1; i < arrlen(sampler->times); i++) { - if (time < sampler->times[i]) { - previous_time = i-1; - next_time = i; - break; - } - } - - float td = sampler->times[next_time]-sampler->times[previous_time]; - float t = (time - sampler->times[previous_time])/td; - - HMM_Vec4 ret; - HMM_Quat qv; - - switch(sampler->type) { - case LINEAR: - return HMM_LerpV4(sampler->data[previous_time],time,sampler->data[next_time]); - break; - case STEP: - return sampler->data[previous_time]; - break; - case CUBICSPLINE: - return sample_cubicspline(sampler,t, previous_time, next_time); - break; - case SLERP: - qv = HMM_SLerp(sampler->data[previous_time].quat, time, sampler->data[next_time].quat); - memcpy(ret.e,qv.e,sizeof(ret.e)); - return ret; - break; - } - return sample_cubicspline(sampler,t, previous_time, next_time); -} diff --git a/anim.h b/anim.h deleted file mode 100644 index 444a9d88..00000000 --- a/anim.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef ANIM_H -#define ANIM_H - -#include "HandmadeMath.h" - -struct keyframe { - double time; - double val; -}; - -#define LINEAR 0 -#define STEP 1 -#define CUBICSPLINE 2 -#define SLERP 3 - -typedef struct sampler { - float *times; - HMM_Vec4 *data; - int type; -} sampler; - -struct anim_channel { - HMM_Vec4 *target; - int comps; - struct sampler *sampler; -}; - -typedef struct animation { - double time; - struct anim_channel *channels; - sampler *samplers; -} animation; - -void animation_run(struct animation *anim, float now); -HMM_Vec4 sample_sampler(sampler *sampler, float time); - -#endif diff --git a/camera.c b/camera.c index 7a6463f7..c2443ccb 100644 --- a/camera.c +++ b/camera.c @@ -1,9 +1,8 @@ -#include "qjs_sdl.h" +#include "sdl.h" #include "qjs_macros.h" #include "cell.h" #include "stb_ds.h" #include "qjs_actor.h" -#include "qjs_sdl_surface.h" #include diff --git a/datastream.c b/datastream.c index 4d5605bc..75abf19a 100644 --- a/datastream.c +++ b/datastream.c @@ -1,25 +1,35 @@ -#define PL_MPEG_IMPLEMENTATION +#include "cell.h" + +#define PL_MPEG_IMPLEMENTATION +#include "pl_mpeg.h" + +struct datastream { + plm_t *plm; + JSValue callback; + JSContext *js; + int width; + int height; +}; + +typedef struct datastream datastream; -#include "datastream.h" #include "cell.h" #include "limits.h" #include #include -#include "font.h" -#include "render.h" #include #include "cbuf.h" -QJSCLASS(datastream,) - void datastream_free(JSRuntime *rt,datastream *ds) { plm_destroy(ds->plm); free(ds); } +QJSCLASS(datastream,) + struct datastream *ds_openvideo(void *raw, size_t rawlen) { struct datastream *ds = malloc(sizeof(*ds)); diff --git a/datastream.h b/datastream.h deleted file mode 100644 index 8e68a0b8..00000000 --- a/datastream.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef DATASTREAM_H -#define DATASTREAM_H - -#include "pl_mpeg.h" -#include -#include "cell.h" - -#include - -struct datastream { - plm_t *plm; - JSValue callback; - JSContext *js; - int width; - int height; -}; - -typedef struct datastream datastream; - -void datastream_free(JSRuntime *rt,datastream *ds); - -struct datastream *ds_openvideo(void *raw, size_t rawlen); -void ds_advance(struct datastream *ds, double); // advance time in seconds -void ds_seek(struct datastream *ds, double); -void ds_pause(struct datastream *ds); -void ds_stop(struct datastream *ds); -int ds_videodone(struct datastream *ds); -double ds_remainingtime(struct datastream *ds); -double ds_length(struct datastream *ds); - -#endif diff --git a/font.c b/font.c deleted file mode 100644 index a8bb6ba8..00000000 --- a/font.c +++ /dev/null @@ -1,325 +0,0 @@ -#include "font.h" - -#include -#include -#include -#include -#include -#include "render.h" - -#include "stb_image_write.h" -#include "stb_rect_pack.h" - -#define STB_TRUETYPE_IMPLEMENTATION -#define STB_TRUETYPE_NO_STDIO -#include "stb_truetype.h" - -#define STB_DS_IMPLEMENTATION -#include "stb_ds.h" - -#include "HandmadeMath.h" - -typedef struct { const char *start, *end; float width; } line_t; -typedef struct { line_t *lines; float max_width; } layout_lines; - -struct sFont *use_font; - -void font_free(JSRuntime *rt, font *f) -{ - if (f->surface) SDL_DestroySurface(f->surface); - free(f); -} - -struct sFont *MakeFont(void *ttf_buffer, size_t len, int height) { - if (!ttf_buffer) - return NULL; - - int packsize = 1024; - - struct sFont *newfont = calloc(1, sizeof(struct sFont)); - newfont->height = height; - - unsigned char *bitmap = malloc(packsize * packsize); - - stbtt_packedchar glyphs[95]; - - stbtt_pack_context pc; - - int pad = 2; - - stbtt_PackBegin(&pc, bitmap, packsize, packsize, 0, pad, NULL); - stbtt_PackFontRange(&pc, ttf_buffer, 0, height, 32, 95, glyphs); - stbtt_PackEnd(&pc); - - stbtt_fontinfo fontinfo; - if (!stbtt_InitFont(&fontinfo, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer, 0))) { -// YughError("Failed to make font %s", fontfile); - } - - int ascent, descent, linegap; - - stbtt_GetFontVMetrics(&fontinfo, &ascent, &descent, &linegap); - float s = stbtt_ScaleForPixelHeight(&fontinfo, height); - newfont->ascent = ascent * s; - newfont->descent = descent * s; /* descent is negative */ - newfont->linegap = linegap * s; - newfont->line_height = (newfont->ascent - newfont->descent) + newfont->linegap; - newfont->surface = SDL_CreateSurface(packsize,packsize, SDL_PIXELFORMAT_RGBA32); - if (!newfont->surface) printf("SDL ERROR: %s\n", SDL_GetError()); - for (int i = 0; i < packsize; i++) - for (int j = 0; j < packsize; j++) - if (!SDL_WriteSurfacePixel(newfont->surface, j, i, 255,255,255,bitmap[i*packsize+j])) - printf("SDLERROR: %s\n", SDL_GetError()); - - for (unsigned char c = 32; c < 127; c++) { - stbtt_packedchar glyph = glyphs[c - 32]; - - rect uv; - uv.x = (glyph.x0) / (float)packsize; - uv.w = (glyph.x1-glyph.x0) / (float)packsize; - uv.y = (glyph.y1) / (float)packsize; - uv.h = (glyph.y0-glyph.y1) / (float)packsize; - newfont->Characters[c].uv = uv; - - rect quad; - quad.x = glyph.xoff; - quad.y = -glyph.yoff2; // Top of glyph relative to baseline - quad.w = glyph.xoff2 - glyph.xoff; - quad.h = glyph.yoff2 - glyph.yoff; // Height from baseline - newfont->Characters[c].quad = quad; - newfont->Characters[c].advance = glyph.xadvance; - } - - free(bitmap); - - return newfont; -} - -layout_lines layout_text_lines(const char *text, font *f, - float letter_spacing, - float wrap, - TEXT_BREAK break_at) -{ - layout_lines out = {0}; - int break_at_word = (break_at == WORD); - - const char *line_start = text; - const char *word_start = text; - float line_width = 0; - float word_width = 0; - - float max_width = 0; - - for (const char *p = text; *p; p++) { - if (*p == '\n') { - line_t L = { line_start, p, line_width }; - arrput(out.lines, L); - if (line_width > max_width) max_width = line_width; - - line_start = p + 1; - word_start = p + 1; - line_width = 0; - word_width = 0; - continue; - } - - unsigned char ch = (unsigned char)*p; - float char_w = f->Characters[ch].advance + letter_spacing; - - if (wrap > 0 && line_width + char_w > wrap) { - const char *break_pt = p; - float break_w = line_width; - - if (break_at_word && *p != ' ' && word_width > 0 && word_start > line_start) { - break_pt = word_start; - break_w = line_width - word_width; - } - - line_t L = { line_start, break_pt, break_w }; - arrput(out.lines, L); - if (break_w > max_width) max_width = break_w; - - line_start = break_pt; - if (break_at_word && *line_start == ' ') line_start++; - - p = line_start - 1; - word_start = line_start; - line_width = 0; - word_width = 0; - continue; - } - - line_width += char_w; - - if (break_at_word) { - if (*p == ' ') { - word_width = 0; - word_start = p + 1; - } else { - word_width += char_w; - } - } - } - - if (line_start < text + strlen(text)) { - line_t L = { line_start, text + strlen(text), line_width }; - arrput(out.lines, L); - if (line_width > max_width) max_width = line_width; - } - - out.max_width = max_width; - return out; -} - -void sdrawCharacter(struct text_vert **buffer, stbtt_packedchar c, HMM_Vec2 cursor, float scale, struct rgba color) { - struct text_vert vert; - -// vert.pos.x = cursor.X + c.leftbearing; -// vert.pos.y = cursor.Y + c.topbearing; -// vert.wh = c.size; - -// if (vert.pos.x > frame.l || vert.pos.y > frame.t || (vert.pos.y + vert.wh.y) < frame.b || (vert.pos.x + vert.wh.x) < frame.l) return; - -// vert.uv.x = c.rect.x; -// vert.uv.y = c.rect.y; -// vert.st.x = c.rect.w; -// vert.st.y = c.rect.h; - rgba2floats(vert.color.e, color); - - arrput(*buffer, vert); -} - -void draw_char_verts(struct text_vert **buffer, struct character c, HMM_Vec2 cursor, colorf color) -{ - // packedchar has - // Adds four verts: bottom left, bottom right, top left, top right - text_vert bl; - bl.pos.x = cursor.X + c.quad.x; - bl.pos.y = cursor.Y + c.quad.y; - bl.uv.x = c.uv.x; - bl.uv.y = c.uv.y; - bl.color = color; - arrput(*buffer, bl); - - - text_vert br = bl; - br.pos.x += c.quad.w; - br.uv.x += c.uv.w; - arrput(*buffer, br); - - text_vert ul = bl; - ul.pos.y += c.quad.h; - ul.uv.y += c.uv.h; - arrput(*buffer, ul); - - text_vert ur = ul; - ur.pos.x = br.pos.x; - ur.uv.x = br.uv.x; - arrput(*buffer, ur); -} - -const char *esc_color(const char *c, struct rgba *color, struct rgba defc) -{ - struct rgba d; - if (!color) color = &d; - if (*c != '\033') return c; - c++; - if (*c != '[') return c; - c++; - if (*c == '0') { - *color = defc; - c++; - return c; - } - else if (!strncmp(c, "38;2;", 5)) { - c += 5; - *color = (struct rgba){0,0,0,255}; - color->r = atoi(c); - c = strchr(c, ';')+1; - color->g = atoi(c); - c = strchr(c,';')+1; - color->b = atoi(c); - c = strchr(c,';')+1; - return c; - } - return c; -} - -// text is a string, font f, wrap is how long a line is before wrapping. -1 to not wrap -HMM_Vec2 measure_text(const char *text, font *f, float letter_spacing, float wrap, TEXT_BREAK break_at, TEXT_ALIGN align) -{ - layout_lines lay = layout_text_lines(text, f, letter_spacing, wrap, break_at); - - float lh = f->line_height; - int line_count = arrlen(lay.lines); - float height = line_count > 0 ? line_count * lh : 0; - - float width = lay.max_width; - if (wrap > 0 && align != LEFT && align != JUSTIFY) { - // For RIGHT or CENTER we might shift lines visually, but width is still max(line.width, wrap ? min(wrap, ...) ). - // Usually you'd report max(wrap, width) or just wrap, depending on how you want containers to size. - } - - HMM_Vec2 dim = { width, height }; - - arrfree(lay.lines); - return dim; -} - -/* pos given in screen coordinates */ -struct text_vert *renderText(const char *text, HMM_Vec2 pos, font *f, colorf color, - float wrap, TEXT_BREAK break_at, TEXT_ALIGN align, - float letter_spacing) -{ - text_vert *buffer = NULL; - float lh = f->line_height; - - layout_lines lay = layout_text_lines(text, f, letter_spacing, wrap, break_at); - line_t *lines = lay.lines; - - HMM_Vec2 cursor = pos; - - for (int i = 0; i < arrlen(lines); i++) { - line_t *L = &lines[i]; - float start_x = pos.x; - float extra_space = 0; - int space_count = 0; - - if (wrap > 0) { - switch (align) { - case RIGHT: start_x = pos.x + wrap - L->width; break; - case CENTER: start_x = pos.x + (wrap - L->width) * 0.5f; break; - case JUSTIFY: - if (i < arrlen(lines) - 1 && *(L->end) != '\n') { - for (const char *p = L->start; p < L->end; p++) if (*p == ' ') space_count++; - if (space_count > 0) extra_space = (wrap - L->width) / space_count; - } - break; - case LEFT: default: break; - } - } - - cursor.x = start_x; - - const char *p = L->start; - while (p < L->end) { - unsigned char ch = (unsigned char)*p; - struct character g = f->Characters[ch]; - - if (!isspace(*p)) draw_char_verts(&buffer, g, cursor, color); - - cursor.x += g.advance; - /* add letter spacing unless this is last char of the line */ - if (p + 1 < L->end) cursor.x += letter_spacing; - if (align == JUSTIFY && *p == ' ') cursor.x += extra_space; - - p++; - } - - cursor.x = pos.x; - cursor.y -= lh; - } - - arrfree(lines); - return buffer; -} diff --git a/font.h b/font.h deleted file mode 100644 index 30f459bf..00000000 --- a/font.h +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef FONT_H -#define FONT_H - -#include "render.h" -#include "HandmadeMath.h" -#include "cell.h" -#include -#include "render.h" - -typedef enum { - LEFT, - RIGHT, - CENTER, - JUSTIFY -} TEXT_ALIGN; - -typedef enum { - WORD, - CHARACTER -} TEXT_BREAK; - -struct text_vert { - HMM_Vec2 pos; - HMM_Vec2 uv; - HMM_Vec4 color; -}; - -typedef struct text_vert text_vert; - -struct text_char { - rect pos; - rect uv; - HMM_Vec4 color; -}; - -struct shader; -struct window; - -struct character { - float advance; - rect quad; - rect uv; - float xoff; - float yoff; - float width; - float height; -}; - -// text data -struct sFont { - uint32_t height; /* in pixels */ - float ascent; // pixels - float descent; // pixels - float linegap; //pixels - float line_height; // pixels - struct character Characters[256]; - SDL_Surface *surface; -}; - -typedef struct sFont font; -typedef struct Character glyph; - -void font_free(JSRuntime *rt,font *f); - -struct sFont *MakeFont(void *data, size_t len, int height); -struct text_vert *renderText(const char *text, HMM_Vec2 pos, font *f, colorf color, float wrap, TEXT_BREAK breakAt, TEXT_ALIGN align, float letter_spacing); -HMM_Vec2 measure_text(const char *text, font *f, float letterSpacing, float wrap, TEXT_BREAK breakAt, TEXT_ALIGN align); - -#endif diff --git a/geometry.c b/geometry.c index 5f60ef35..2b7adc4c 100644 --- a/geometry.c +++ b/geometry.c @@ -4,9 +4,6 @@ #include #include #include "HandmadeMath.h" -#include "font.h" -#include "sprite.h" -#include "transform.h" #include "stb_ds.h" extern void *get_gpu_buffer(JSContext *js, JSValue argv, size_t *stride, size_t *size); @@ -92,10 +89,6 @@ JSC_CCALL(geometry_rect_expand, return rect2js(js,c); ) -// Helper functions for geometry operations - - - static inline void add_quad(text_vert **verts, rect *restrict src, rect *restrict dst) { text_vert v = (text_vert){ @@ -555,18 +548,6 @@ struct quad_buffers quad_buffers_new(int verts) return b; } -int sort_sprite(const sprite *a, const sprite *b) -{ - if (a->layer != b->layer) return a->layer - b->layer; - - if (a->pos.Y != b->pos.Y) - return (b->pos.Y - a->pos.Y); - - if (JS_VALUE_GET_PTR(a->image) != JS_VALUE_GET_PTR(b->image)) - return JS_VALUE_GET_PTR(a->image) < JS_VALUE_GET_PTR(b->image) ? -1 : 1; - return 0; -} - JSC_CCALL(geometry_rect_transform, // argv[0] = world‐space rect rect r = js2rect(js, argv[0]); diff --git a/graphics.c b/graphics.c index dd9f7638..07b5f98a 100644 --- a/graphics.c +++ b/graphics.c @@ -1,7 +1,6 @@ #include "cell.h" #include "prosperon.h" #include "HandmadeMath.h" -#include "datastream.h" #define STB_IMAGE_IMPLEMENTATION #define STBI_FAILURE_USERMSG diff --git a/model.c b/model.c index 6622d23f..30e71e84 100644 --- a/model.c +++ b/model.c @@ -1,9 +1,7 @@ -#include "model.h" +#include "cell.h" #include "stb_ds.h" -#include "render.h" - #include "HandmadeMath.h" #include "math.h" @@ -16,6 +14,128 @@ #include #include + +struct keyframe { + double time; + double val; +}; + +#define LINEAR 0 +#define STEP 1 +#define CUBICSPLINE 2 +#define SLERP 3 + +typedef struct sampler { + float *times; + HMM_Vec4 *data; + int type; +} sampler; + +struct anim_channel { + HMM_Vec4 *target; + int comps; + struct sampler *sampler; +}; + +typedef struct animation { + double time; + struct anim_channel *channels; + sampler *samplers; +} animation; + + +HMM_Vec4 sample_cubicspline(sampler *sampler, float t, int prev, int next) +{ + HMM_Vec4 ret; + HMM_Quat qv = HMM_SLerp(HMM_QV4(sampler->data[prev]), t, HMM_QV4(sampler->data[next])); + memcpy(ret.e, qv.e, sizeof(ret.e)); + return ret; +} + +HMM_Vec4 sample_sampler(sampler *sampler, float time) +{ + if (arrlen(sampler->data) == 0) return v4zero; + if (arrlen(sampler->data) == 1) return sampler->data[0]; + int previous_time=0; + int next_time=0; + + for (int i = 1; i < arrlen(sampler->times); i++) { + if (time < sampler->times[i]) { + previous_time = i-1; + next_time = i; + break; + } + } + + float td = sampler->times[next_time]-sampler->times[previous_time]; + float t = (time - sampler->times[previous_time])/td; + + HMM_Vec4 ret; + HMM_Quat qv; + + switch(sampler->type) { + case LINEAR: + return HMM_LerpV4(sampler->data[previous_time],time,sampler->data[next_time]); + break; + case STEP: + return sampler->data[previous_time]; + break; + case CUBICSPLINE: + return sample_cubicspline(sampler,t, previous_time, next_time); + break; + case SLERP: + qv = HMM_SLerp(sampler->data[previous_time].quat, time, sampler->data[next_time].quat); + memcpy(ret.e,qv.e,sizeof(ret.e)); + return ret; + break; + } + return sample_cubicspline(sampler,t, previous_time, next_time); +} + + +void animation_run(struct animation *anim, float now) +{ + float elapsed = now - anim->time; + elapsed = fmod(elapsed,2); + if (!anim->channels) return; + + for (int i = 0; i < arrlen(anim->channels); i++) { + struct anim_channel *ch = anim->channels+i; + HMM_Vec4 s = sample_sampler(ch->sampler, elapsed); + *(ch->target) = s; + } +} + + +#define MAT_POS 0 +#define MAT_UV 1 +#define MAT_NORM 2 +#define MAT_BONE 3 +#define MAT_WEIGHT 4 +#define MAT_COLOR 5 +#define MAT_TAN 6 +#define MAT_ANGLE 7 +#define MAT_WH 8 +#define MAT_ST 9 +#define MAT_PPOS 10 +#define MAT_SCALE 11 +#define MAT_INDEX 100 + +typedef struct md5joint { + struct md5joint *parent; + HMM_Vec4 pos; + HMM_Quat rot; + HMM_Vec4 scale; + HMM_Mat4 t; +} md5joint; + +typedef struct skin { + md5joint *joints; + HMM_Mat4 *invbind; + HMM_Mat4 binds[50]; /* binds = joint * invbind */ + animation *anim; +} skin; + SDL_GPUBuffer *texcoord_floats(float *f, int n) { return NULL; diff --git a/model.h b/model.h deleted file mode 100644 index f7f2e69b..00000000 --- a/model.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef MODEL_H -#define MODEL_H - -#include "HandmadeMath.h" -#include "transform.h" -#include "anim.h" - -#include "cgltf.h" - -#define MAT_POS 0 -#define MAT_UV 1 -#define MAT_NORM 2 -#define MAT_BONE 3 -#define MAT_WEIGHT 4 -#define MAT_COLOR 5 -#define MAT_TAN 6 -#define MAT_ANGLE 7 -#define MAT_WH 8 -#define MAT_ST 9 -#define MAT_PPOS 10 -#define MAT_SCALE 11 -#define MAT_INDEX 100 - -typedef struct md5joint { - struct md5joint *parent; - HMM_Vec4 pos; - HMM_Quat rot; - HMM_Vec4 scale; - HMM_Mat4 t; -} md5joint; - -typedef struct skin { - md5joint *joints; - HMM_Mat4 *invbind; - HMM_Mat4 binds[50]; /* binds = joint * invbind */ - animation *anim; -} skin; - -//sg_buffer accessor2buffer(cgltf_accessor *a, int type); -skin *make_gltf_skin(cgltf_skin *skin, cgltf_data *data); -void skin_calculate(skin *sk); - -/*sg_buffer float_buffer(float *f, int v); -sg_buffer index_buffer(float *f, int verts); -sg_buffer texcoord_floats(float *f, int n); -sg_buffer par_idx_buffer(uint32_t *i, int v); -sg_buffer normal_floats(float *f, int n); -sg_buffer ubyten_buffer(float *f, int v); -sg_buffer ubyte_buffer(float *f, int v); -sg_buffer joint_buf(float *f, int v); -sg_buffer weight_buf(float *f, int v); -*/ -#endif diff --git a/prosperon.c b/prosperon.c index 63118632..ad0d8241 100644 --- a/prosperon.c +++ b/prosperon.c @@ -232,3 +232,12 @@ JSValue rect2js(JSContext *js,rect rect) { JS_SetPropertyStr(js, obj, "height", number2js(js, rect.h)); return obj; } + +float *rgba2floats(float *r, struct rgba c) +{ + r[0] = (float)c.r / RGBA_MAX; + r[1] = (float)c.g / RGBA_MAX; + r[2] = (float)c.b / RGBA_MAX; + r[3] = (float)c.a / RGBA_MAX; + return r; +} diff --git a/prosperon.cm b/prosperon.cm index 93ea83e7..165e9371 100644 --- a/prosperon.cm +++ b/prosperon.cm @@ -2,9 +2,9 @@ var prosperon = {} // This file is hard coded for the SDL GPU case -var video = use('sdl_video') +var video = use('sdl/video') var surface = use('surface') -var sdl_gpu = use('sdl_gpu') +var sdl_gpu = use('sdl/gpu') var io = use('cellfs') var geometry = use('geometry') var blob = use('blob') diff --git a/prosperon.h b/prosperon.h index 9c167237..53745715 100644 --- a/prosperon.h +++ b/prosperon.h @@ -1,44 +1,34 @@ #ifndef PROSPERON_H #define PROSPERON_H +#include "cell.h" #include "HandmadeMath.h" -#include "sprite.h" -#include "transform.h" - -// Common data structures struct lrtb { float l; float r; float t; float b; }; - typedef struct lrtb lrtb; + +lrtb js2lrtb(JSContext *js, JSValue v); +JSValue lrtb2js(JSContext *js, lrtb r); + +struct text_vert { + HMM_Vec2 pos; + HMM_Vec2 uv; + HMM_Vec4 color; +}; + typedef struct text_vert text_vert; + +JSValue quads_to_mesh(JSContext *js, text_vert *argv); + typedef HMM_Vec4 colorf; typedef SDL_FRect rect; typedef SDL_Rect irect; -JSValue rect2js(JSContext *js, rect r); -rect js2rect(JSContext *js, JSValue v); -HMM_Vec2 js2vec2(JSContext *js, JSValue v); -JSValue vec22js(JSContext *js, HMM_Vec2 v); -colorf js2color(JSContext *js, JSValue v); -double js2number(JSContext *js, JSValue v); -JSValue number2js(JSContext *js, double n); -SDL_Window *js2SDL_Window(JSContext *js, JSValue v); -JSValue SDL_Window2js(JSContext *js, SDL_Window *w); -void *get_gpu_buffer(JSContext *js, JSValue argv, size_t *stride, size_t *size); -double js_getnum_str(JSContext *js, JSValue v, const char *str); -HMM_Vec3 js2vec3(JSContext *js, JSValue v); -JSValue vec32js(JSContext *js, HMM_Vec3 v); -HMM_Vec4 js2vec4(JSContext *js, JSValue v); -JSValue vec42js(JSContext *js, HMM_Vec4 v); -JSValue make_gpu_buffer(JSContext *js, void *data, size_t size, int type, int elements, int copy, int index); -JSValue make_quad_indices_buffer(JSContext *js, int quads); -JSClassID js_SDL_Surface_id; - // Common conversion functions used across modules JSValue rect2js(JSContext *js, rect r); JSValue vec22js(JSContext *js, HMM_Vec2 v); @@ -49,8 +39,6 @@ JSValue color2js(JSContext *js, colorf c); JSValue number2js(JSContext *js, double d); JSValue angle2js(JSContext *js, double a); -double js_getnum_str(JSContext *js, JSValue v, const char *str); - rect js2rect(JSContext *js, JSValue v); HMM_Vec2 js2vec2(JSContext *js, JSValue v); HMM_Vec3 js2vec3(JSContext *js, JSValue v); @@ -60,7 +48,17 @@ colorf js2color(JSContext *js, JSValue v); double js2number(JSContext *js, JSValue v); double js2angle(JSContext *js, JSValue v); -lrtb js2lrtb(JSContext *js, JSValue v); -JSValue lrtb2js(JSContext *js, lrtb r); +#define RGBA_MAX 255 + +struct rgba { + unsigned char r; + unsigned char g; + unsigned char b; + unsigned char a; +}; + +typedef struct rgba rgba; + +float *rgba2floats(float *r, struct rgba c); #endif \ No newline at end of file diff --git a/qjs_geometry.h b/qjs_geometry.h deleted file mode 100644 index 0beb139b..00000000 --- a/qjs_geometry.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef QJS_GEOMETRY_H -#define QJS_GEOMETRY_H - -JSValue quads_to_mesh(JSContext *js, text_vert *buffer); - -#endif \ No newline at end of file diff --git a/qjs_imgui.h b/qjs_imgui.h deleted file mode 100644 index 37d24679..00000000 --- a/qjs_imgui.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef QJS_IMGUI_H -#define QJS_IMGUI_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -// Function to process SDL events for ImGui -void gui_input(SDL_Event *e); - -#ifdef __cplusplus -} -#endif - -#endif // QJS_IMGUI_H \ No newline at end of file diff --git a/qjs_renderer.c.old b/qjs_renderer.c.old index a5954490..561a8f88 100644 --- a/qjs_renderer.c.old +++ b/qjs_renderer.c.old @@ -6,7 +6,7 @@ #include #include #include "HandmadeMath.h" -#include "qjs_sdl.h" +#include "sdl.h" #include void SDL_Renderer_free() { @@ -274,8 +274,13 @@ JSC_CCALL(renderer_geometry, JSValue color = JS_GetPropertyStr(js,argv[1], "color"); JSValue uv = JS_GetPropertyStr(js,argv[1], "uv"); JSValue indices = JS_GetPropertyStr(js,argv[1], "indices"); - int vertices = js_getnum_str(js, argv[1], "vertices"); - int count = js_getnum_str(js, argv[1], "count"); + JSValue js_vertices = JS_GetPropertyStr(js,argv[1], "vertices"); + JSValue js_count = JS_GetPropertyStr(js,argv[1], "count"); + int vertices, count; + JS_ToInt32(js, &vertices, js_vertices); + JS_ToInt32(js, &count, js_count); + JS_FreeValue(js, js_vertices); + JS_FreeValue(js, js_count); size_t pos_stride, indices_stride, uv_stride, color_stride; void *posdata = get_gpu_buffer(js,pos, &pos_stride, NULL); diff --git a/qjs_sdl_surface.h b/qjs_sdl_surface.h deleted file mode 100644 index 6961ba49..00000000 --- a/qjs_sdl_surface.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef QJS_SDL_SURFACE_H -#define QJS_SDL_SURFACE_H - -#include "cell.h" -#include - -// Functions generated by QJSCLASS macro -JSValue SDL_Surface2js(JSContext *js, SDL_Surface *s); -SDL_Surface *js2SDL_Surface(JSContext *js, JSValue val); - -// Free function for SDL_Surface -void SDL_Surface_free(JSRuntime *rt, SDL_Surface *s); - -// Class ID for SDL_Surface -extern JSClassID js_SDL_Surface_id; - -#endif diff --git a/qoi.c b/qoi.c index ad93e76b..a3d59d1e 100644 --- a/qoi.c +++ b/qoi.c @@ -1,7 +1,7 @@ #define QOI_IMPLEMENTATION #include "qoi.h" #include "cell.h" -#include "qjs_sdl.h" +#include "sdl.h" #include #include diff --git a/render.c b/render.c deleted file mode 100644 index f2406ebd..00000000 --- a/render.c +++ /dev/null @@ -1,12 +0,0 @@ -#include "render.h" - -viewstate globalview = {0}; - -float *rgba2floats(float *r, struct rgba c) -{ - r[0] = (float)c.r / RGBA_MAX; - r[1] = (float)c.g / RGBA_MAX; - r[2] = (float)c.b / RGBA_MAX; - r[3] = (float)c.a / RGBA_MAX; - return r; -} diff --git a/render.h b/render.h deleted file mode 100644 index 41baf220..00000000 --- a/render.h +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef OPENGL_RENDER_H -#define OPENGL_RENDER_H - -#include "HandmadeMath.h" -#include - -#define RGBA_MAX 255 - -extern struct rgba color_white; -extern struct rgba color_black; -extern struct rgba color_clear; -extern int TOPLEFT; - -typedef struct viewstate { - HMM_Mat4 v; - HMM_Mat4 p; - HMM_Mat4 vp; -} viewstate; - -extern viewstate globalview; - -void capture_screen(int x, int y, int w, int h, const char *path); - -void gif_rec_start(int w, int h, int cpf, int bitdepth); -void gif_rec_end(const char *path); - -struct uv_n { - unsigned short u; - unsigned short v; -}; - -struct st_n { - struct uv_n s; - struct uv_n t; -}; - -struct rgba { - unsigned char r; - unsigned char g; - unsigned char b; - unsigned char a; -}; - -typedef struct rgba rgba; -typedef HMM_Vec4 rgbaf; -typedef HMM_Vec4 colorf; - -// rectangles are always defined with [x,y] in the bottom left -typedef SDL_FRect rect; -typedef SDL_Rect irect; - -float *rgba2floats(float *r, struct rgba c); - -static inline float lerp(float f, float a, float b) -{ - return a * (1.0-f)+(b*f); -} - -#endif diff --git a/qjs_sdl.h b/sdl.h similarity index 90% rename from qjs_sdl.h rename to sdl.h index b341bb5b..94ccc154 100644 --- a/qjs_sdl.h +++ b/sdl.h @@ -4,6 +4,9 @@ #include #include "cell.h" +SDL_Window *js2SDL_Window(JSContext *js, JSValue v); +JSValue SDL_Window2js(JSContext *js, SDL_Window *w); + SDL_PixelFormat str2pixelformat(const char *str); SDL_PixelFormat js2pixelformat(JSContext *js, JSValue v); JSValue pixelformat2js(JSContext *js, SDL_PixelFormat format); diff --git a/sdl_audio.c b/sdl/audio.c similarity index 100% rename from sdl_audio.c rename to sdl/audio.c diff --git a/sdl_gpu.c b/sdl/gpu.c similarity index 99% rename from sdl_gpu.c rename to sdl/gpu.c index ca282218..f9af110b 100644 --- a/sdl_gpu.c +++ b/sdl/gpu.c @@ -1,11 +1,9 @@ -#include "qjs_sdl_gpu.h" #include "prosperon.h" +#include "sdl.h" #include "qjs_macros.h" -#include "qjs_sdl_surface.h" #include "quickjs.h" #include -#include "render.h" #include "cell.h" // Macro for GPU wrapper classes that need cleanup @@ -42,9 +40,6 @@ JSValue SDL_##SDLTYPE##2js(JSContext *js, JSValue device, SDL_##SDLTYPE *member) return j; \ } -extern double js2number(JSContext *js, JSValue v); -extern double js_getnum_str(JSContext *js, JSValue obj, const char *str); - // Simple string conversion helper const char *js2cstring(JSContext *js, JSValue v) { diff --git a/sdl_input.c b/sdl/input.c similarity index 99% rename from sdl_input.c rename to sdl/input.c index 9a9f85f7..7c5e1e1a 100644 --- a/sdl_input.c +++ b/sdl/input.c @@ -1,9 +1,7 @@ -#include "qjs_sdl_input.h" #include "qjs_macros.h" #include "cell.h" #include "stb_ds.h" #include "qjs_actor.h" -#include "qjs_imgui.h" #include "wota.h" #include "qjs_wota.h" diff --git a/sdl_surface.c b/sdl/surface.c similarity index 99% rename from sdl_surface.c rename to sdl/surface.c index 1f5f0eba..fa5320ee 100644 --- a/sdl_surface.c +++ b/sdl/surface.c @@ -1,4 +1,3 @@ -#include "qjs_sdl_surface.h" #include "cell.h" #include "prosperon.h" #include @@ -6,7 +5,7 @@ #include #include #include -#include "qjs_sdl.h" +#include "sdl.h" #define STB_DXT_IMPLEMENTATION #include "stb_dxt.h" diff --git a/sdl_video.c b/sdl/video.c similarity index 99% rename from sdl_video.c rename to sdl/video.c index e9112a73..3bd8f7f7 100644 --- a/sdl_video.c +++ b/sdl/video.c @@ -1,8 +1,5 @@ #include "cell.h" -#include "qjs_sdl_surface.h" #include "qjs_actor.h" -#include "sprite.h" -#include "transform.h" #include "prosperon.h" @@ -13,7 +10,7 @@ #include #include #include -#include "qjs_sdl.h" +#include "sdl.h" // SDL Window free function void SDL_Window_free(JSRuntime *rt, SDL_Window *w) diff --git a/sdl_video.ce b/sdl/video.ce similarity index 99% rename from sdl_video.ce rename to sdl/video.ce index bcc0bbec..3afe9628 100644 --- a/sdl_video.ce +++ b/sdl/video.ce @@ -1,4 +1,4 @@ -var video = use('sdl_video'); +var video = use('sdl/video'); var imgui = use('imgui'); log.console("BAD") diff --git a/simplex.c b/simplex.c.old similarity index 99% rename from simplex.c rename to simplex.c.old index 02e4cc3c..1a0d6cf2 100644 --- a/simplex.c +++ b/simplex.c.old @@ -7,7 +7,6 @@ Published originally as a Garrysmod Lua Extension under the pseudonym Levybreak */ #include -#include "simplex.h" double Noise(genericNoise func, int len, double inputs[]) { diff --git a/simplex.h b/simplex.h deleted file mode 100644 index 50b74203..00000000 --- a/simplex.h +++ /dev/null @@ -1,39 +0,0 @@ -//externs made available by simplex.c - -#ifndef SIMPLEX_H_INCLUDED -#define SIMPLEX_H_INCLUDED - -#define SIMPLEX_X 0 -#define SIMPLEX_Y 1 -#define SIMPLEX_Z 2 -#define SIMPLEX_W 3 - -typedef double (*noise2Dptr)(double, double); -typedef double (*noise3Dptr)(double, double, double); -typedef double (*noise4Dptr)(double, double, double, double); - -typedef double (*noiseNDptr)(int, double[]); - -typedef union NoiseUnion { - noise2Dptr p2; - noise3Dptr p3; - noise4Dptr p4; - noiseNDptr pn; -} genericNoise; - -double Noise2D(double x, double y); -double Noise3D(double x, double y, double z); -double Noise4D(double x, double y, double z, double w); - -double GBlur1D(double stdDev, double x); -double GBlur2D(double stdDev, double x, double y); - -double Noise(genericNoise func, int len, double args[]); - -double TurbulentNoise(genericNoise func, int direction, int iterations, int len, double args[]); -double FractalSumNoise(genericNoise func, int iterations, int len, double args[]); -double FractalSumAbsNoise(genericNoise func, int iterations, int len, double args[]); - -double octave_3d(double x, double y, double z, int octaves, double persistence); - -#endif diff --git a/sound.cm b/sound.cm index 1cb05be8..fbe38e47 100644 --- a/sound.cm +++ b/sound.cm @@ -43,7 +43,7 @@ audio.cry = function cry(file) { // // pump + periodic cleanup // -var ss = use('sdl_audio') +var ss = use('sdl/audio') var feeder = ss.open_stream("playback") feeder.set_format({format:"f32", channels:2, samplerate:44100}) feeder.resume() diff --git a/spline.c b/spline.c index 2dbdc1b7..b047f389 100644 --- a/spline.c +++ b/spline.c @@ -1,8 +1,6 @@ -#include "spline.h" #include "stb_ds.h" #include -#include "transform.h" -#include "math.h" +#include "HandmadeMath.h" /* ------------------------------------------------------------------------- Cubic Spline Basis Matrices diff --git a/sprite.c b/sprite.c index 45fc1a72..5b69faff 100644 --- a/sprite.c +++ b/sprite.c @@ -1,10 +1,22 @@ -#include "qjs_sprite.h" #include "prosperon.h" -#include "qjs_macros.h" +#include "cell.h" -#include "sprite.h" #include "HandmadeMath.h" +struct sprite{ + HMM_Vec2 pos; // x,y coordinates of the sprite + HMM_Vec2 center; + HMM_Vec2 skew; + HMM_Vec2 scale; + float rotation; + HMM_Mat2 affine; + JSValue image; // the JS image + int layer; // layer this sprite draws onto + HMM_Vec4 color; // color in 0-1f +}; + +typedef struct sprite sprite; + sprite *make_sprite(void) { sprite *sprite = calloc(sizeof(*sprite),1); diff --git a/sprite.h b/sprite.h deleted file mode 100644 index e032b703..00000000 --- a/sprite.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef SPRITE_H -#define SPRITE_H - -#include "HandmadeMath.h" -#include "cell.h" - -struct sprite{ - HMM_Vec2 pos; // x,y coordinates of the sprite - HMM_Vec2 center; - HMM_Vec2 skew; - HMM_Vec2 scale; - float rotation; - HMM_Mat2 affine; - JSValue image; // the JS image - int layer; // layer this sprite draws onto - HMM_Vec4 color; // color in 0-1f -}; - -typedef struct sprite sprite; - -sprite *make_sprite(void); -void sprite_free(JSRuntime *rt, sprite *sprite); -void sprite_apply(sprite *sprite); - -#endif diff --git a/staef.c b/staef.c index f56cb3b1..8b55655c 100644 --- a/staef.c +++ b/staef.c @@ -1,25 +1,381 @@ -#include "font.h" -#include "qjs_macros.h" -#include "HandmadeMath.h" -#include "render.h" -#include "stb_ds.h" #include "cell.h" -#include "qjs_sdl.h" +#include "prosperon.h" +#include "HandmadeMath.h" +#include "stb_ds.h" + +#include "sdl.h" #include #include -#include "qjs_geometry.h" -// External functions from jsffi.c -typedef HMM_Vec4 colorf; -extern colorf js2color(JSContext *js, JSValue v); -extern JSValue vec22js(JSContext *js, HMM_Vec2 v); -extern HMM_Vec2 js2vec2(JSContext *js, JSValue v); -extern rect js2rect(JSContext *js, JSValue v); -extern double js2number(JSContext *js, JSValue v); -extern JSValue number2js(JSContext *js, double g); -extern void *js_get_blob_data(JSContext *js, size_t *len, JSValue v); -extern JSValue js_new_blob_stoned_copy(JSContext *js, void *data, size_t size); -extern int uncaught_exception(JSContext *js, JSValue ret); +#include +#include +#include +#include +#include + +#include "stb_image_write.h" +#include "stb_rect_pack.h" + +#define STB_TRUETYPE_IMPLEMENTATION +#define STB_TRUETYPE_NO_STDIO +#include "stb_truetype.h" + +#define STB_DS_IMPLEMENTATION +#include "stb_ds.h" + +#include "HandmadeMath.h" + +typedef enum { + LEFT, + RIGHT, + CENTER, + JUSTIFY +} TEXT_ALIGN; + +typedef enum { + WORD, + CHARACTER +} TEXT_BREAK; + +struct text_char { + rect pos; + rect uv; + HMM_Vec4 color; +}; + +struct shader; +struct window; + +struct character { + float advance; + rect quad; + rect uv; + float xoff; + float yoff; + float width; + float height; +}; + +// text data +struct sFont { + uint32_t height; /* in pixels */ + float ascent; // pixels + float descent; // pixels + float linegap; //pixels + float line_height; // pixels + struct character Characters[256]; + SDL_Surface *surface; +}; + +typedef struct sFont font; +typedef struct Character glyph; + + +typedef struct { const char *start, *end; float width; } line_t; +typedef struct { line_t *lines; float max_width; } layout_lines; + +struct sFont *use_font; + +void font_free(JSRuntime *rt, font *f) +{ + if (f->surface) SDL_DestroySurface(f->surface); + free(f); +} + +struct sFont *MakeFont(void *ttf_buffer, size_t len, int height) { + if (!ttf_buffer) + return NULL; + + int packsize = 1024; + + struct sFont *newfont = calloc(1, sizeof(struct sFont)); + newfont->height = height; + + unsigned char *bitmap = malloc(packsize * packsize); + + stbtt_packedchar glyphs[95]; + + stbtt_pack_context pc; + + int pad = 2; + + stbtt_PackBegin(&pc, bitmap, packsize, packsize, 0, pad, NULL); + stbtt_PackFontRange(&pc, ttf_buffer, 0, height, 32, 95, glyphs); + stbtt_PackEnd(&pc); + + stbtt_fontinfo fontinfo; + if (!stbtt_InitFont(&fontinfo, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer, 0))) { +// YughError("Failed to make font %s", fontfile); + } + + int ascent, descent, linegap; + + stbtt_GetFontVMetrics(&fontinfo, &ascent, &descent, &linegap); + float s = stbtt_ScaleForPixelHeight(&fontinfo, height); + newfont->ascent = ascent * s; + newfont->descent = descent * s; /* descent is negative */ + newfont->linegap = linegap * s; + newfont->line_height = (newfont->ascent - newfont->descent) + newfont->linegap; + newfont->surface = SDL_CreateSurface(packsize,packsize, SDL_PIXELFORMAT_RGBA32); + if (!newfont->surface) printf("SDL ERROR: %s\n", SDL_GetError()); + for (int i = 0; i < packsize; i++) + for (int j = 0; j < packsize; j++) + if (!SDL_WriteSurfacePixel(newfont->surface, j, i, 255,255,255,bitmap[i*packsize+j])) + printf("SDLERROR: %s\n", SDL_GetError()); + + for (unsigned char c = 32; c < 127; c++) { + stbtt_packedchar glyph = glyphs[c - 32]; + + rect uv; + uv.x = (glyph.x0) / (float)packsize; + uv.w = (glyph.x1-glyph.x0) / (float)packsize; + uv.y = (glyph.y1) / (float)packsize; + uv.h = (glyph.y0-glyph.y1) / (float)packsize; + newfont->Characters[c].uv = uv; + + rect quad; + quad.x = glyph.xoff; + quad.y = -glyph.yoff2; // Top of glyph relative to baseline + quad.w = glyph.xoff2 - glyph.xoff; + quad.h = glyph.yoff2 - glyph.yoff; // Height from baseline + newfont->Characters[c].quad = quad; + newfont->Characters[c].advance = glyph.xadvance; + } + + free(bitmap); + + return newfont; +} + +layout_lines layout_text_lines(const char *text, font *f, + float letter_spacing, + float wrap, + TEXT_BREAK break_at) +{ + layout_lines out = {0}; + int break_at_word = (break_at == WORD); + + const char *line_start = text; + const char *word_start = text; + float line_width = 0; + float word_width = 0; + + float max_width = 0; + + for (const char *p = text; *p; p++) { + if (*p == '\n') { + line_t L = { line_start, p, line_width }; + arrput(out.lines, L); + if (line_width > max_width) max_width = line_width; + + line_start = p + 1; + word_start = p + 1; + line_width = 0; + word_width = 0; + continue; + } + + unsigned char ch = (unsigned char)*p; + float char_w = f->Characters[ch].advance + letter_spacing; + + if (wrap > 0 && line_width + char_w > wrap) { + const char *break_pt = p; + float break_w = line_width; + + if (break_at_word && *p != ' ' && word_width > 0 && word_start > line_start) { + break_pt = word_start; + break_w = line_width - word_width; + } + + line_t L = { line_start, break_pt, break_w }; + arrput(out.lines, L); + if (break_w > max_width) max_width = break_w; + + line_start = break_pt; + if (break_at_word && *line_start == ' ') line_start++; + + p = line_start - 1; + word_start = line_start; + line_width = 0; + word_width = 0; + continue; + } + + line_width += char_w; + + if (break_at_word) { + if (*p == ' ') { + word_width = 0; + word_start = p + 1; + } else { + word_width += char_w; + } + } + } + + if (line_start < text + strlen(text)) { + line_t L = { line_start, text + strlen(text), line_width }; + arrput(out.lines, L); + if (line_width > max_width) max_width = line_width; + } + + out.max_width = max_width; + return out; +} + +void sdrawCharacter(struct text_vert **buffer, stbtt_packedchar c, HMM_Vec2 cursor, float scale, struct rgba color) { + struct text_vert vert; + +// vert.pos.x = cursor.X + c.leftbearing; +// vert.pos.y = cursor.Y + c.topbearing; +// vert.wh = c.size; + +// if (vert.pos.x > frame.l || vert.pos.y > frame.t || (vert.pos.y + vert.wh.y) < frame.b || (vert.pos.x + vert.wh.x) < frame.l) return; + +// vert.uv.x = c.rect.x; +// vert.uv.y = c.rect.y; +// vert.st.x = c.rect.w; +// vert.st.y = c.rect.h; + rgba2floats(vert.color.e, color); + + arrput(*buffer, vert); +} + +void draw_char_verts(struct text_vert **buffer, struct character c, HMM_Vec2 cursor, colorf color) +{ + // packedchar has + // Adds four verts: bottom left, bottom right, top left, top right + text_vert bl; + bl.pos.x = cursor.X + c.quad.x; + bl.pos.y = cursor.Y + c.quad.y; + bl.uv.x = c.uv.x; + bl.uv.y = c.uv.y; + bl.color = color; + arrput(*buffer, bl); + + + text_vert br = bl; + br.pos.x += c.quad.w; + br.uv.x += c.uv.w; + arrput(*buffer, br); + + text_vert ul = bl; + ul.pos.y += c.quad.h; + ul.uv.y += c.uv.h; + arrput(*buffer, ul); + + text_vert ur = ul; + ur.pos.x = br.pos.x; + ur.uv.x = br.uv.x; + arrput(*buffer, ur); +} + +const char *esc_color(const char *c, struct rgba *color, struct rgba defc) +{ + struct rgba d; + if (!color) color = &d; + if (*c != '\033') return c; + c++; + if (*c != '[') return c; + c++; + if (*c == '0') { + *color = defc; + c++; + return c; + } + else if (!strncmp(c, "38;2;", 5)) { + c += 5; + *color = (struct rgba){0,0,0,255}; + color->r = atoi(c); + c = strchr(c, ';')+1; + color->g = atoi(c); + c = strchr(c,';')+1; + color->b = atoi(c); + c = strchr(c,';')+1; + return c; + } + return c; +} + +// text is a string, font f, wrap is how long a line is before wrapping. -1 to not wrap +HMM_Vec2 measure_text(const char *text, font *f, float letter_spacing, float wrap, TEXT_BREAK break_at, TEXT_ALIGN align) +{ + layout_lines lay = layout_text_lines(text, f, letter_spacing, wrap, break_at); + + float lh = f->line_height; + int line_count = arrlen(lay.lines); + float height = line_count > 0 ? line_count * lh : 0; + + float width = lay.max_width; + if (wrap > 0 && align != LEFT && align != JUSTIFY) { + // For RIGHT or CENTER we might shift lines visually, but width is still max(line.width, wrap ? min(wrap, ...) ). + // Usually you'd report max(wrap, width) or just wrap, depending on how you want containers to size. + } + + HMM_Vec2 dim = { width, height }; + + arrfree(lay.lines); + return dim; +} + +/* pos given in screen coordinates */ +struct text_vert *renderText(const char *text, HMM_Vec2 pos, font *f, colorf color, + float wrap, TEXT_BREAK break_at, TEXT_ALIGN align, + float letter_spacing) +{ + text_vert *buffer = NULL; + float lh = f->line_height; + + layout_lines lay = layout_text_lines(text, f, letter_spacing, wrap, break_at); + line_t *lines = lay.lines; + + HMM_Vec2 cursor = pos; + + for (int i = 0; i < arrlen(lines); i++) { + line_t *L = &lines[i]; + float start_x = pos.x; + float extra_space = 0; + int space_count = 0; + + if (wrap > 0) { + switch (align) { + case RIGHT: start_x = pos.x + wrap - L->width; break; + case CENTER: start_x = pos.x + (wrap - L->width) * 0.5f; break; + case JUSTIFY: + if (i < arrlen(lines) - 1 && *(L->end) != '\n') { + for (const char *p = L->start; p < L->end; p++) if (*p == ' ') space_count++; + if (space_count > 0) extra_space = (wrap - L->width) / space_count; + } + break; + case LEFT: default: break; + } + } + + cursor.x = start_x; + + const char *p = L->start; + while (p < L->end) { + unsigned char ch = (unsigned char)*p; + struct character g = f->Characters[ch]; + + if (!isspace(*p)) draw_char_verts(&buffer, g, cursor, color); + + cursor.x += g.advance; + /* add letter spacing unless this is last char of the line */ + if (p + 1 < L->end) cursor.x += letter_spacing; + if (align == JUSTIFY && *p == ' ') cursor.x += extra_space; + + p++; + } + + cursor.x = pos.x; + cursor.y -= lh; + } + + arrfree(lines); + return buffer; +} + // QuickJS class for font QJSCLASS(font,) diff --git a/tests/draw2d.ce b/tests/draw2d.ce index 8be36290..c8cd7307 100644 --- a/tests/draw2d.ce +++ b/tests/draw2d.ce @@ -6,7 +6,7 @@ var input = use('input') input.watch($_) // Create SDL video actor -var video_actor = use('sdl_video'); +var video_actor = use('sdl/video'); var window_id = null; var renderer_id = null; diff --git a/tests/webcam.ce b/tests/webcam.ce index 2628ad8d..3f6af29c 100644 --- a/tests/webcam.ce +++ b/tests/webcam.ce @@ -8,7 +8,7 @@ var surface = use('surface') input.watch($_) // Create SDL video actor -var video_actor = use('sdl_video'); +var video_actor = use('sdl/video'); var camera = use('camera') var window_id = null; diff --git a/transform.c b/transform.c index 3476776d..c7e7fa2f 100644 --- a/transform.c +++ b/transform.c @@ -4,9 +4,30 @@ #include "stb_ds.h" #include #include -#include "transform.h" #include "HandmadeMath.h" +#define VEC2_FMT "[%g,%g]" +#define VEC2_MEMS(s) (s).x, (s).y + +#define TR_FMT "(pos) " HMMFMT_VEC3 " scale " HMMFMT_VEC3 +#define TR_PRINT(tr) HMMPRINT_VEC3(tr->pos), HMMPRINT_VEC3(tr->scale) + +typedef struct transform { + HMM_Vec3 pos; + HMM_Vec3 scale; + HMM_Quat rotation; + HMM_Mat4 cache; + HMM_Mat4 gcache; + int dirty; + struct transform *parent; + struct transform **children; + + JSValue self; + JSValue jsparent; + JSValue *jschildren; + JSValue change_hook; +} transform; + static transform **dirties; @@ -72,6 +93,12 @@ void clean_all(JSContext *js) arrsetlen(dirties,0); } +void transform_apply(transform *t) +{ + t->dirty = 1; + arrput(dirties,t); +} + void transform_move(transform *t, HMM_Vec3 v) { t->pos = HMM_AddV3(t->pos, v); @@ -137,12 +164,6 @@ rect transform2rect(transform *t) return r; } -void transform_apply(transform *t) -{ - t->dirty = 1; - arrput(dirties,t); -} - HMM_Quat angle2rotation(float angle) { return HMM_QFromAxisAngle_RH(vBKWD, angle); diff --git a/transform.h b/transform.h deleted file mode 100644 index a2c0a079..00000000 --- a/transform.h +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef TRANSFORM_H -#define TRANSFORM_H - -#include "HandmadeMath.h" -#include "cell.h" -#include "render.h" - -typedef struct transform { - HMM_Vec3 pos; - HMM_Vec3 scale; - HMM_Quat rotation; - HMM_Mat4 cache; - HMM_Mat4 gcache; - int dirty; - struct transform *parent; - struct transform **children; - - JSValue self; - JSValue jsparent; - JSValue *jschildren; - JSValue change_hook; -} transform; - -void clean_all(JSContext *js); - -transform *make_transform(void); -void transform_free(JSRuntime *rt,transform *t); - -void transform_apply(transform *t); - -#define VEC2_FMT "[%g,%g]" -#define VEC2_MEMS(s) (s).x, (s).y - -#define TR_FMT "(pos) " HMMFMT_VEC3 " scale " HMMFMT_VEC3 -#define TR_PRINT(tr) HMMPRINT_VEC3(tr->pos), HMMPRINT_VEC3(tr->scale) - -void transform_move(transform *t, HMM_Vec3 v); -HMM_Vec3 transform_direction(transform *t, HMM_Vec3 dir); - -/* Transform a position via the matrix */ -HMM_Vec2 mat_t_pos(HMM_Mat3 m, HMM_Vec2 pos); -/* Transform a direction via the matrix - does not take into account translation of matrix */ -HMM_Vec2 mat_t_dir(HMM_Mat3 m, HMM_Vec2 dir); - -HMM_Vec2 mat_up(HMM_Mat3 m); -HMM_Vec2 mat_right(HMM_Mat3 m); -float vec_angle(HMM_Vec2 a, HMM_Vec2 b); -float vec_dirangle(HMM_Vec2 a, HMM_Vec2 b); - -HMM_Vec3 mat3_t_pos(HMM_Mat4 m, HMM_Vec3 pos); -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); -rect transform2rect(transform *t); - -transform mat2transform(HMM_Mat4 m); - -HMM_Quat angle2rotation(float angle); - -#endif