From 51438a53288bb6630dd93fb93fa157ccd329518e Mon Sep 17 00:00:00 2001 From: John Alanbrook Date: Sun, 12 Nov 2023 02:01:42 +0000 Subject: [PATCH] update docs --- docs/editor.md | 4 -- docs/game.md | 65 +++++++----------- scripts/entity.js | 2 +- source/engine/2dphysics.c | 126 +++++++++++++---------------------- source/engine/2dphysics.h | 16 ++--- source/engine/3d/model.c | 2 +- source/engine/HandmadeMath.h | 22 +++++- source/engine/gameobject.c | 34 ++++++++-- source/engine/gameobject.h | 12 ++-- source/engine/sprite.c | 25 +++---- 10 files changed, 146 insertions(+), 162 deletions(-) diff --git a/docs/editor.md b/docs/editor.md index ba3b1da..1c8c836 100644 --- a/docs/editor.md +++ b/docs/editor.md @@ -8,10 +8,6 @@ In addition, a window showing each entity underneath that entity are shown. The desktop is the topmost object that exists in the editor. Instead of editing specific files, you simply load them into your desktop, and go from there. This makes it easier to see two different entities simultaneously so you can ensure changes to one are congruous with the vision for the others. -## Ur-types - -Ur-types are what are loaded into the game world. They are templates for creating entities. - ## *'s and %'s When a '*' is seen next to an entity's name, that means it is altered compared to its ur-type and is unsaved. There are a number of ways to take care of a '*'. If you do not do one of the below, something on the entity will be lost. diff --git a/docs/game.md b/docs/game.md index 7e95332..93cca14 100644 --- a/docs/game.md +++ b/docs/game.md @@ -1,45 +1,36 @@ -# Yugine +# Primum -The yugine essentially is made of a sequence of levels. Levels can be -nested, they can be streamed in, or loaded one at a time. Levels are -made of levels. +Games are made of entities. Entities are made of components. Components can be thought of as properties that entities poses; entities are a collection of components. Components include things like drawables (textures, sprites), physical colliders, and more. -Different "modes" of using the engine has unique sequences of level -loading orders. Each level has an associated script file. Level -loading functions call the script file, as well as the level file. The -level file can be considered to be a container of objects that the -associated script file can access. +Entities can have control of other entities, in which case the one in control is the 'master' and the controlee the 'padawan'. When a master moves or rotates, all padawans move and rotate with it. -* Game start - 1. Engine scripts - 2. config.js - 3. game.lvl & game.js +The first and most masterful entity is the Primum. The Primum has no components, and its rotation and position are zero. It defines the center of the game. -* Editor - 1. Engine scripts - 2. config.js - 3. editor.js +## Scripting -* Editor play - * F5 debug.lvl. Used for custom debug level testing. If doesn't exist, game.lvl is loaded. - * F6 game.lvl - * F7 Currently edited level +There are a number of script hooks which are ran at particular times of engine loading. When a game starts ... + - config.js + - game.js -## Playing, editing, debugging +When the editor starts ... + - editorconfig.js -Playing is playing your game. Controls are what are specified for your game. +F5 can be pressed in the editor to test the game. In that case ... + - config.js + - debug.js -In debug builds, additional debug controls are available. For example, F12 brings up GUI debug boxes. C-M-f puts you into a flying camera mode, without pausing your game. +And when play mode is left ... + - dbgret.js -The game can be paused to edit it. Most editor controls are available here, all of them essentially except for loading new levels, clearing the level, etc. An object can be clicked on and edited, objects can be moved, etc. +## Ur-types +Ur-types are what are loaded into the game world. They are templates for creating entities. Ur-types are defined by providing the engine with .jso files. -A prefab can be opened up to edit on its own, without breaking the currently played level. +If you have a 'enemy.jso' file, then on game start you can spawn an enemy via 'Primum.spawn(ur.enemy)'. The 'ur' object holds all ur-types the game knows about. -In edit mode, there are no running scripts; only editing them. +Ur-types are loaded on demand, or can be preloaded with 'prototypes.generate_ur()'. -## The ECS system - -There are two distinct items in the Primum Machina: the Entity, and the Component. Components give qualities to Entities. An Entity is any real, tangible thing in the universe, and so every entity has a position. Components do not necessarily have a position; they can be things like the image that draws where the entity is located, and colliders that allow the entity to respond with the world. +## The ECS system, revisited +There are two distinct items in the Primum: the Entity, and the Component. Components give qualities to Entities. An Entity is any real, tangible thing in the universe, and so every entity has a position. Components do not necessarily have a position; they can be things like the image that draws where the entity is located, and colliders that allow the entity to respond with the world. ### Components The most "bare metal" are the components. These are essentially hooks into the engine that tell it how to do particular things. For example, to render a sprite, Javascript does no rendering, but rather tells the engine to create an image and render it in a particular spot. Javascript does the accounting to make or destroy the sprite as needed - but besides that initial startup, no scripting is done. @@ -88,9 +79,7 @@ Ur-ur, the thing all Ur-types derive from - Variant 2A, overwritten values from Variant 2 - Ur-type 2 -All ur-types and variants can be created in the world, where they become a true blue ENTITY. Entities can be under entities infinitely. - -Ur-types have a specific combination of components. When a component is removed from an entity, the link to its ur-type breaks. +All ur-types and variants can be created in the world, where they become an entity. Entities can be under entities infinitely. (Master-padawan) Entities have access to their ur-type through their .ur parameter. Each ur-type and variant likewise stores a list of entities that have been created from them. @@ -101,17 +90,9 @@ ur.type : the actual object ur.instances : instances of it ur.tag : the full name of it -### Loading traits -Traits are defined by code and a data file. When an Ur-type is extended with a trait, the code is run, and then the data file contains modifications and - -### Creating entities -Entities are like real world representations of an Ur-type. Ur-types exist only theoretically, but can then be spawned into a true entity in the game world. - +### Diverting entities An entity can diverge from its ur-type. When this happens, you can either revert the entity, copy how it's changed to its ur-type, or promote it to its own ur-type. -### Efficiency of all this -It is extremely cheap and fast to create entities. Ur-types work as a defined way for the engine to make an object, and can even cache deleted copies of them. - ## Resources Assets can generally be used just with their filename. It will be loaded with default values. However, how the engine interprets it can be altered with a sidecar file, named "filename.asset", so "ball.png" will be modified via "ball.png.asset". These are typical JSON files. For images, specify gamma, if it's a sprite or texture, etc, for sound, specify its gain, etc. diff --git a/scripts/entity.js b/scripts/entity.js index 1a8ca5c..b199085 100644 --- a/scripts/entity.js +++ b/scripts/entity.js @@ -562,7 +562,7 @@ var gameobject = { obj.level = undefined; obj.reparent(level); - Object.hide(obj, 'ur','body', 'components', 'objects', '_ed', 'level'); + Object.hide(obj, 'ur','body', 'components', 'objects', '_ed', 'level', 'timers'); Object.dainty_assign(obj, this); obj.sync(); diff --git a/source/engine/2dphysics.c b/source/engine/2dphysics.c index 8279f6b..b3a6603 100644 --- a/source/engine/2dphysics.c +++ b/source/engine/2dphysics.c @@ -198,7 +198,7 @@ struct phys2d_circle *Make2DCircle(int go) { struct phys2d_circle *new = malloc(sizeof(struct phys2d_circle)); new->radius = 10.f; - new->offset = cpvzero; + new->offset = v2zero; new->shape.shape = cpSpaceAddShape(space, cpCircleShapeNew(id2go(go)->body, new->radius, cpvzero)); new->shape.debugdraw = phys2d_dbgdrawcircle; @@ -211,66 +211,33 @@ struct phys2d_circle *Make2DCircle(int go) { } float phys2d_circle_moi(struct phys2d_circle *c, float m) { - return cpMomentForCircle(m, 0, c->radius, c->offset); + return 1; + //TODO: Calculate correctly + //return cpMomentForCircle(m, 0, c->radius, c->offset); } void phys2d_circledel(struct phys2d_circle *c) { phys2d_shape_del(&c->shape); } -cpVect world2go(struct gameobject *go, cpVect worldpos) { - cpTransform T = {0}; - cpVect pos = cpBodyGetPosition(go->body); - worldpos.x -= pos.x; - worldpos.y -= pos.y; - // worldpos.x /= go->scale; - // worldpos.y /= go->scale; - float angle = cpBodyGetAngle(go->body); - T.a = go->flipx * cos(-angle) / go->scale; - T.b = sin(-angle) / go->scale; - T.c = -sin(-angle) / go->scale; - T.d = go->flipy * cos(-angle) / go->scale; - worldpos = cpTransformPoint(T, worldpos); - - return worldpos; -} - -cpVect go2world(struct gameobject *go, cpVect gopos) { - cpVect pos = cpBodyGetPosition(go->body); - float angle = cpBodyGetAngle(go->body); - cpTransform T = {0}; - T.a = go->scale * go->flipx * cos(angle); - T.b = sin(angle) * go->scale * go->flipx; - T.c = -sin(angle) * go->scale * go->flipy; - T.d = go->scale * go->flipy * cos(angle); - T.tx = pos.x; - T.ty = pos.y; - return cpTransformPoint(T, gopos); -} - -cpVect gotransformpoint(struct gameobject *go, cpVect point) { - point.x *= go->scale * go->flipx; - point.y *= go->scale * go->flipy; - return point; -} - -cpVect bodytransformpoint(cpBody *body, cpVect offset) { - cpVect pos = cpBodyGetPosition(body); - float d = sqrt(pow(offset.x, 2.f) + pow(offset.y, 2.f)); - float a = atan2(offset.y, offset.x) + cpBodyGetAngle(body); - pos.x += d * cos(a); - pos.y += d * sin(a); +HMM_Vec2 bodytransformpoint(cpBody *body, HMM_Vec2 offset) { + HMM_Vec2 pos; + pos.cp = cpBodyGetPosition(body); + float d = sqrt(pow(offset.X, 2.f) + pow(offset.Y, 2.f)); + float a = atan2(offset.Y, offset.X) + cpBodyGetAngle(body); + pos.X += d * cos(a); + pos.Y += d * sin(a); return pos; } void phys2d_dbgdrawcpcirc(cpCircleShape *c) { - cpVect pos = bodytransformpoint(cpShapeGetBody(c), cpCircleShapeGetOffset(c)); + HMM_Vec2 pos = bodytransformpoint(cpShapeGetBody(c), (HMM_Vec2)cpCircleShapeGetOffset(c)); float radius = cpCircleShapeGetRadius(c); struct rgba color = shape_color(c); float seglen = cpShapeGetSensor(c) ? 5 : -1; - draw_circle(pos, radius, 1, color, seglen); + draw_circle(pos.cp, radius, 1, color, seglen); color.a = col_alpha; - draw_circle(pos,radius,radius,color,-1); + draw_circle(pos.cp,radius,radius,color,-1); } void phys2d_dbgdrawcircle(struct phys2d_circle *circle) { @@ -280,11 +247,10 @@ void phys2d_dbgdrawcircle(struct phys2d_circle *circle) { void phys2d_applycircle(struct phys2d_circle *circle) { struct gameobject *go = id2go(circle->shape.go); - float radius = circle->radius * go->scale; - cpVect offset = gotransformpoint(go, circle->offset); - + float radius = circle->radius * HMM_LenSqrV2(go->scale.XY); cpCircleShapeSetRadius(circle->shape.shape, radius); - cpCircleShapeSetOffset(circle->shape.shape, offset); + + cpCircleShapeSetOffset(circle->shape.shape, HMM_MulV2(go->scale.XY, circle->offset).cp); } /************* BOX2D ************/ @@ -295,8 +261,7 @@ struct phys2d_box *Make2DBox(int go) { new->w = 50.f; new->h = 50.f; new->r = 0.f; - new->offset[0] = 0.f; - new->offset[1] = 0.f; + new->offset = v2zero; new->shape.go = go; new->shape.apply = phys2d_applybox; phys2d_applybox(new); @@ -310,14 +275,14 @@ float phys2d_box_moi(struct phys2d_box *box, float m) { return cpMomentForBox(m, box->w, box->h); } -cpTransform go2transform(struct gameobject *go, cpVect offset, float angle) { - cpTransform T = {0}; - T.a = cos(angle) * go->scale * go->flipx; - T.b = -sin(angle) * go->scale * go->flipx; - T.c = sin(angle) * go->scale * go->flipy; - T.d = cos(angle) * go->scale * go->flipy; - T.tx = offset.x * go->scale; - T.ty = offset.y * go->scale; +cpTransform trs2cpt(HMM_Vec2 t, float angle, HMM_Vec2 s) { + cpTransform T; + T.a = cos(angle) * s.X; + T.b = -sin(angle) * s.X; + T.c = sin(angle) * s.Y; + T.d = cos(angle) * s.Y; + T.tx = t.X * s.X; + T.ty = t.Y * s.Y; return T; } @@ -328,10 +293,7 @@ void phys2d_boxdel(struct phys2d_box *box) { void phys2d_applybox(struct phys2d_box *box) { phys2d_boxdel(box); struct gameobject *go = id2go(box->shape.go); - cpVect off; - off.x = box->offset[0]; - off.y = box->offset[1]; - cpTransform T = go2transform(id2go(box->shape.go), off, box->rotation); + cpTransform T = trs2cpt(box->offset, box->rotation, id2go(box->shape.go)->scale.XY); float hh = box->h / 2.f; float hw = box->w / 2.f; cpVect verts[4] = {{-hw, -hh}, {hw, -hh}, {hw, hh}, {-hw, hh}}; @@ -341,10 +303,10 @@ void phys2d_applybox(struct phys2d_box *box) { void phys2d_dbgdrawbox(struct phys2d_box *box) { int n = cpPolyShapeGetCount(box->shape.shape); - cpVect points[n * 2]; + HMM_Vec2 points[n * 2]; for (int i = 0; i < n; i++) - points[i] = bodytransformpoint(cpShapeGetBody(box->shape.shape), cpPolyShapeGetVert(box->shape.shape, i)); + points[i] = bodytransformpoint(cpShapeGetBody(box->shape.shape), cpPolyShapeGetVert(box->shape.shape, i)).cp; struct rgba c = shape_color(box->shape.shape); struct rgba cl = c; @@ -386,7 +348,7 @@ void phys2d_polydel(struct phys2d_poly *poly) { } void phys2d_polyaddvert(struct phys2d_poly *poly) { - arrput(poly->points, cpvzero); + arrput(poly->points, v2zero); } void phys2d_poly_setverts(struct phys2d_poly *poly, cpVect *verts) { @@ -395,8 +357,10 @@ void phys2d_poly_setverts(struct phys2d_poly *poly, cpVect *verts) { arrfree(poly->points); arrsetlen(poly->points, arrlen(verts)); - for (int i = 0; i < arrlen(verts); i++) - poly->points[i] = verts[i]; + for (int i = 0; i < arrlen(verts); i++) { + poly->points[i].X = verts[i].x; + poly->points[i].Y = verts[i].y; + } phys2d_applypoly(poly); } @@ -405,7 +369,7 @@ void phys2d_applypoly(struct phys2d_poly *poly) { if (arrlen(poly->points) <= 0) return; struct gameobject *go = id2go(poly->shape.go); - cpTransform T = go2transform(go, cpvzero, 0); + cpTransform T = trs2cpt((HMM_Vec2){0,0}, 0, (HMM_Vec2){1,1}); cpPolyShapeSetVerts(poly->shape.shape, arrlen(poly->points), poly->points, T); cpPolyShapeSetRadius(poly->shape.shape, poly->radius); @@ -453,7 +417,7 @@ struct phys2d_edge *Make2DEdge(int go) { float phys2d_edge_moi(struct phys2d_edge *edge, float m) { float moi = 0; for (int i = 0; i < arrlen(edge->points) - 1; i++) - moi += cpMomentForSegment(m, edge->points[i], edge->points[i + 1], edge->thickness); + moi += cpMomentForSegment(m, edge->points[i].cp, edge->points[i + 1].cp, edge->thickness); return moi; } @@ -463,7 +427,7 @@ void phys2d_edgedel(struct phys2d_edge *edge) { } void phys2d_edgeaddvert(struct phys2d_edge *edge) { - arrput(edge->points, cpvzero); + arrput(edge->points, v2zero); if (arrlen(edge->points) > 1) arrput(edge->shapes, cpSpaceAddShape(space, cpSegmentShapeNew(id2go(edge->shape.go)->body, cpvzero, cpvzero, edge->thickness))); @@ -486,7 +450,7 @@ void phys2d_edge_rmvert(struct phys2d_edge *edge, int index) { } if (index != arrlen(edge->points)) { - cpSegmentShapeSetEndpoints(edge->shapes[index - 1], edge->points[index - 1], edge->points[index]); + cpSegmentShapeSetEndpoints(edge->shapes[index - 1], edge->points[index - 1].cp, edge->points[index].cp); } cpSpaceRemoveShape(space, edge->shapes[index - 1]); @@ -498,7 +462,7 @@ void phys2d_edge_rmvert(struct phys2d_edge *edge, int index) { void phys2d_edge_setvert(struct phys2d_edge *edge, int index, cpVect val) { assert(arrlen(edge->points) > index && index >= 0); - edge->points[index] = val; + edge->points[index].cp = val; phys2d_applyedge(edge); } @@ -520,12 +484,12 @@ void phys2d_applyedge(struct phys2d_edge *edge) { struct gameobject *go = id2go(edge->shape.go); for (int i = 0; i < arrlen(edge->shapes); i++) { - cpVect a = gotransformpoint(go, edge->points[i]); - cpVect b = gotransformpoint(go, edge->points[i + 1]); - cpSegmentShapeSetEndpoints(edge->shapes[i], a, b); + HMM_Vec2 a = goscale(go, edge->points[i]); + HMM_Vec2 b = goscale(go, edge->points[i+1]); + cpSegmentShapeSetEndpoints(edge->shapes[i], a.cp, b.cp); cpSegmentShapeSetRadius(edge->shapes[i], edge->thickness); if (i > 0 && i < arrlen(edge->shapes) - 1) - cpSegmentShapeSetNeighbors(edge->shapes[i], gotransformpoint(go, edge->points[i - 1]), gotransformpoint(go, edge->points[i + 2])); + cpSegmentShapeSetNeighbors(edge->shapes[i], goscale(go,edge->points[i-1]).cp, goscale(go,edge->points[i+2]).cp); go_shape_apply(NULL, edge->shapes[i], go); cpShapeSetUserData(edge->shapes[i], &edge->shape); } @@ -544,11 +508,11 @@ void phys2d_dbgdrawedge(struct phys2d_edge *edge) { if (arrlen(edge->shapes) < 1) return; - cpVect drawpoints[arrlen(edge->points)]; + HMM_Vec2 drawpoints[arrlen(edge->points)]; struct gameobject *go = id2go(edge->shape.go); for (int i = 0; i < arrlen(edge->points); i++) { - drawpoints[i] = gotransformpoint(go, edge->points[i]); + drawpoints[i] = goscale(go, edge->points[i]); drawpoints[i] = bodytransformpoint(cpShapeGetBody(edge->shapes[0]), drawpoints[i]); } diff --git a/source/engine/2dphysics.h b/source/engine/2dphysics.h index d72e9dc..5a61edf 100644 --- a/source/engine/2dphysics.h +++ b/source/engine/2dphysics.h @@ -33,21 +33,21 @@ struct phys2d_shape { /* Circles are the fastest collier type */ struct phys2d_circle { float radius; - cpVect offset; + HMM_Vec2 offset; struct phys2d_shape shape; }; /* A single segment */ struct phys2d_segment { - float a[2]; - float b[2]; + HMM_Vec2 a; + HMM_Vec2 b; float thickness; struct phys2d_shape shape; }; /* A convex polygon; defined as the convex hull around the given set of points */ struct phys2d_poly { - cpVect *points; + HMM_Vec2 *points; float radius; struct phys2d_shape shape; }; @@ -56,15 +56,15 @@ struct phys2d_poly { struct phys2d_box { float w; float h; - float offset[2]; + HMM_Vec2 offset; float rotation; - float r; + float r; /* radius */ struct phys2d_shape shape; }; /* An edge with no volume. Cannot collide with each other. Join to make levels. Static only. */ struct phys2d_edge { - cpVect *points; + HMM_Vec2 *points; float thickness; cpShape **shapes; int closed; /* True if the first and last points should be connected */ @@ -141,8 +141,6 @@ int *phys2d_query_box_points(cpVect pos, cpVect wh, cpVect *points, int n); void flush_collide_cbs(); void phys2d_reindex_body(cpBody *body); -cpVect world2go(struct gameobject *go, cpVect worldpos); -cpVect go2world(struct gameobject *go, cpVect gopos); extern unsigned int category_masks[32]; void set_cat_mask(int cat, unsigned int mask); int phys2d_in_air(cpBody *body); diff --git a/source/engine/3d/model.c b/source/engine/3d/model.c index 231cd6c..cc27d19 100644 --- a/source/engine/3d/model.c +++ b/source/engine/3d/model.c @@ -323,7 +323,7 @@ void draw_drawmodel(struct drawmodel *dm) if (!dm->model) return; struct gameobject *go = id2go(dm->go); cpVect pos = cpBodyGetPosition(go->body); - HMM_Mat4 scale = HMM_Scale(id2go(dm->go)->scale3); + HMM_Mat4 scale = HMM_Scale(id2go(dm->go)->scale); HMM_Mat4 trans = HMM_M4D(1.f); trans.Elements[3][2] = -pos.x; trans.Elements[3][1] = pos.y; diff --git a/source/engine/HandmadeMath.h b/source/engine/HandmadeMath.h index c0adb96..d7b8f44 100644 --- a/source/engine/HandmadeMath.h +++ b/source/engine/HandmadeMath.h @@ -96,6 +96,8 @@ #ifndef HANDMADE_MATH_H #define HANDMADE_MATH_H +#include + /* 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! */ @@ -230,6 +232,8 @@ typedef union HMM_Vec2 { float Elements[2]; + cpVect cp; + #ifdef __cplusplus inline float &operator[](const int &Index) { return Elements[Index]; @@ -237,6 +241,8 @@ typedef union HMM_Vec2 { #endif } HMM_Vec2; +const HMM_Vec2 v2zero = {0,0}; + typedef union HMM_Vec3 { struct { @@ -286,6 +292,8 @@ typedef union HMM_Vec3 { #endif } HMM_Vec3; +const HMM_Vec3 v3zero = {0,0,0}; + typedef union HMM_Vec4 { struct { @@ -1135,7 +1143,6 @@ static inline HMM_Mat3 HMM_SubM3(HMM_Mat3 Left, HMM_Mat3 Right) { } static inline HMM_Vec3 HMM_MulM3V3(HMM_Mat3 Matrix, HMM_Vec3 Vector) { - HMM_Vec3 Result; Result.X = Vector.Elements[0] * Matrix.Columns[0].X; @@ -1163,6 +1170,19 @@ static inline HMM_Mat3 HMM_MulM3(HMM_Mat3 Left, HMM_Mat3 Right) { return Result; } +/*static inline HMM_Mat3 HMM_VMulM3(int c, ...) +{ + HMM_Mat3 res = HMM_M3D(1); + va_list args; + va_start(args, c); + for (int i = 0; i < c; i++) { + HMM_Mat3 m = va_arg(args, HMM_Mat3); + res = HMM_MulM3(m, res); + } + va_end(args); + return res; +} +*/ static inline HMM_Mat3 HMM_MulM3F(HMM_Mat3 Matrix, float Scalar) { HMM_Mat3 Result; diff --git a/source/engine/gameobject.c b/source/engine/gameobject.c index 3adeb3a..82752a8 100644 --- a/source/engine/gameobject.c +++ b/source/engine/gameobject.c @@ -85,11 +85,36 @@ HMM_Mat3 transform2d2mat(transform2d t) r.Columns[0] = (HMM_Vec3){cos(t.angle), sin(t.angle), 0}; r.Columns[1] = (HMM_Vec3){-sin(t.angle), cos(t.angle), 0}; - m = HMM_MulM3(s, r); - m = HMM_MulM3(m, p); + m = HMM_MulM3(r, s); + m = HMM_MulM3(p, m); return m; } +HMM_Vec2 go2world(struct gameobject *go, HMM_Vec2 pos) +{ + return HMM_MulM3V3(t_go2world(go), (HMM_Vec3){pos.X, pos.Y, 1.0}).XY; +} + +HMM_Vec2 world2go(struct gameobject *go, HMM_Vec2 pos) +{ + return HMM_MulM3V3(t_world2go(go), (HMM_Vec3){pos.X, pos.Y, 1.0}).XY; +} + +HMM_Vec2 goscale(struct gameobject *go, HMM_Vec2 pos); +{ + return HMM_MulV2(go->scale.XY, pos); +} + +HMM_Mat3 t_go2world(struct gameobject *go) +{ + return transform2d2mat(go2t(go)); +} + +HMM_Mat3 t_world2go(struct gameobject *go) +{ + return HMM_InvGeneralM3(transform2d2mat(go2t(go))); +} + int pos2gameobject(cpVect pos) { cpShape *hit = phys2d_query_pos(pos); @@ -127,7 +152,7 @@ transform2d go2t(gameobject *go) cpVect p = cpBodyGetPosition(go->body); t.pos.X = p.x; t.pos.Y = p.y; t.angle = cpBodyGetAngle(go->body); - t.scale = (HMM_Vec2){go->scale, go->scale}; + t.scale = go->scale.XY; return t; } @@ -224,8 +249,7 @@ static void velocityFn(cpBody *body, cpVect gravity, cpFloat damping, cpFloat dt int MakeGameobject() { struct gameobject go = { - .scale = 1.f, - .scale3 = (HMM_Vec3){1.f,1.f,1.f}, + .scale = (HMM_Vec3){1.f,1.f,1.f}, .bodytype = CP_BODY_TYPE_STATIC, .maxvelocity = INFINITY, .maxangularvelocity = INFINITY, diff --git a/source/engine/gameobject.h b/source/engine/gameobject.h index 789e39a..ac09b63 100644 --- a/source/engine/gameobject.h +++ b/source/engine/gameobject.h @@ -25,8 +25,7 @@ HMM_Mat3 transform2d2mat(transform2d t); typedef struct gameobject { cpBodyType bodytype; int next; - float scale; - HMM_Vec3 scale3; + HMM_Vec3 scale; float mass; float f; /* friction */ float e; /* elasticity */ @@ -34,8 +33,6 @@ typedef struct gameobject { float maxangularvelocity; int gravity; float damping; - int flipx; /* 1 or -1 */ - int flipy; int sensor; unsigned int layer; cpShapeFilter filter; @@ -61,6 +58,13 @@ void gameobject_set_sensor(int id, int sensor); HMM_Vec2 go2pos(struct gameobject *go); float go2angle(struct gameobject *go); transform2d go2t(gameobject *go); +HMM_Vec2 go2world(struct gameobject *go, HMM_Vec2 pos); +HMM_Vec2 world2go(struct gameobject *go, HMM_Vec2 pos); + +HMM_Mat3 t_go2world(struct gameobject *go); +HMM_Mat3 t_world2go(struct gameobject *go); +HMM_Vec2 goscale(struct gameobject *go, HMM_Vec2 pos); +HMM_Vec2 gotpos(struct gameobject *go, HMM_Vec2 pos); struct gameobject *get_gameobject_from_id(int id); struct gameobject *id2go(int id); diff --git a/source/engine/sprite.c b/source/engine/sprite.c index 4490d06..c2ff9a9 100644 --- a/source/engine/sprite.c +++ b/source/engine/sprite.c @@ -201,25 +201,18 @@ void tex_draw(struct Texture *tex, HMM_Mat3 m, struct glrect r, struct rgba colo {0.0,1.0}, {1.0,1.0}, }; - HMM_Vec2 t_scale = { tex->width * st_s_w(r), //*size.X; tex->height * st_s_h(r) // * size.Y }; - m = HMM_MulM3(m, HMM_ScaleM3(t_scale)); for (int i = 0; i < 4; i++) { -/* sposes[i] = HMM_AddV2(sposes[i], offset); - sposes[i] = HMM_MulV2(sposes[i], t_scale); - sposes[i] = HMM_MulM2V2(rot, sposes[i]); - sposes[i] = HMM_AddV2(sposes[i], pos); - verts[i].pos = sposes[i]; -*/ HMM_Vec3 v = HMM_MulM3V3(m, (HMM_Vec3){sposes[i].X, sposes[i].Y, 1.0}); verts[i].pos = (HMM_Vec2){v.X, v.Y}; verts[i].color = color; } + if (!wrap) { verts[0].uv.X = r.s0; verts[0].uv.Y = r.t1; @@ -253,14 +246,18 @@ void sprite_draw(struct sprite *sprite) { struct gameobject *go = id2go(sprite->go); if (sprite->tex) { - cpVect cpos = cpBodyGetPosition(go->body); - HMM_Vec2 pos = (HMM_Vec2){cpos.x, cpos.y}; - HMM_Vec2 size = (HMM_Vec2){sprite->size.X * go->scale * go->flipx, sprite->size.Y * go->scale * go->flipy}; transform2d t = go2t(id2go(sprite->go)); HMM_Mat3 m = transform2d2mat(t); - m.Columns[2].X += sprite->pos.X; - m.Columns[2].Y += sprite->pos.Y; - tex_draw(sprite->tex, transform2d2mat(t), sprite->frame, sprite->color, 0, pos, 0); + + HMM_Mat3 ss = HMM_M3D(1); + ss.Columns[0].X = sprite->size.X * sprite->tex->width * st_s_w(sprite->frame); + ss.Columns[1].Y = sprite->size.Y * sprite->tex->height * st_s_h(sprite->frame); + HMM_Mat3 ts = HMM_M3D(1); + ts.Columns[2] = (HMM_Vec3){sprite->pos.X, sprite->pos.Y, 1}; + + HMM_Mat3 sm = HMM_MulM3(ss, ts); + m = HMM_MulM3(m, sm); + tex_draw(sprite->tex, m, sprite->frame, sprite->color, 0, (HMM_Vec2){0,0}, 0); } }