merge sokol

This commit is contained in:
2023-08-23 04:34:36 +00:00
282 changed files with 667776 additions and 23600 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1,100 +1,149 @@
#ifndef TWODPHYSICS_H
#define TWODPHYSICS_H
#include "script.h"
#include <chipmunk/chipmunk.h>
#include "render.h"
struct gameobject;
extern cpBody *ballBody;
extern float phys2d_gravity;
extern int physOn;
extern cpSpace *space;
extern struct rgba color_white;
extern struct rgba color_black;
extern struct rgba disabled_color;
extern struct rgba dynamic_color;
extern struct rgba kinematic_color;
extern struct rgba static_color;
extern struct rgba sleep_color;
struct phys2d_shape {
cpShape *shape;
struct gameobject *go;
cpShape *shape;
int go;
void *data;
void (*debugdraw)(void *data);
float (*moi)(void *data, float mass);
};
/* Circles are the fastest collier type */
struct phys2d_circle {
float radius;
float offset[2];
struct phys2d_shape shape;
float radius;
cpVect offset;
struct phys2d_shape shape;
};
/* A single segment */
struct phys2d_segment {
float a[2];
float b[2];
float thickness;
struct phys2d_shape shape;
};
struct phys2d_box {
float w;
float h;
float offset[2];
float r;
struct phys2d_shape shape;
};
struct phys2d_edge {
int n;
float *points;
float thickness;
cpShape **shapes;
struct phys2d_shape shape;
float a[2];
float b[2];
float thickness;
struct phys2d_shape shape;
};
/* A convex polygon; defined as the convex hull around the given set of points */
struct phys2d_poly {
int n;
float *points;
float radius;
struct phys2d_shape shape;
cpVect *points;
float radius;
struct phys2d_shape shape;
};
struct phys2d_circle *Make2DCircle(struct gameobject *go);
void phys2d_circleinit(struct phys2d_circle *circle, struct gameobject *go);
/* A box shape; a type of a polygon collider */
struct phys2d_box {
float w;
float h;
float offset[2];
float rotation;
float r;
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;
float thickness;
cpShape **shapes;
int closed; /* True if the first and last points should be connected */
struct phys2d_shape shape;
int draws;
};
struct phys2d_circle *Make2DCircle(int go);
void phys2d_circledel(struct phys2d_circle *c);
void phys2d_applycircle(struct phys2d_circle *circle);
void phys2d_dbgdrawcircle(struct phys2d_circle *circle);
void circle_gui(struct phys2d_circle *circle);
float phys2d_circle_moi(struct phys2d_circle *c, float m);
struct phys2d_segment *Make2DSegment(struct gameobject *go);
void phys2d_seginit(struct phys2d_segment *seg, struct gameobject *go);
void phys2d_segdel(struct phys2d_segment *seg);
void phys2d_applyseg(struct phys2d_segment *seg);
void phys2d_dbgdrawseg(struct phys2d_segment *seg);
void segment_gui(struct phys2d_segment *seg);
struct phys2d_box *Make2DBox(struct gameobject *go);
void phys2d_boxinit(struct phys2d_box *box, struct gameobject *go);
struct phys2d_box *Make2DBox(int go);
void phys2d_boxdel(struct phys2d_box *box);
void phys2d_applybox(struct phys2d_box *box);
void phys2d_dbgdrawbox(struct phys2d_box *box);
void box_gui(struct phys2d_box *box);
float phys2d_box_moi(struct phys2d_box *box, float m);
struct phys2d_poly *Make2DPoly(struct gameobject *go);
void phys2d_polyinit(struct phys2d_poly *poly, struct gameobject *go);
struct phys2d_poly *Make2DPoly(int go);
void phys2d_polydel(struct phys2d_poly *poly);
void phys2d_applypoly(struct phys2d_poly *poly);
void phys2d_dbgdrawpoly(struct phys2d_poly *poly);
void phys2d_polyaddvert(struct phys2d_poly *poly);
void poly_gui(struct phys2d_poly *poly);
void phys2d_poly_setverts(struct phys2d_poly *poly, cpVect *verts);
float phys2d_poly_moi(struct phys2d_poly *poly, float m);
struct phys2d_edge *Make2DEdge(struct gameobject *go);
void phys2d_edgeinit(struct phys2d_edge *edge, struct gameobject *go);
struct phys2d_edge *Make2DEdge(int go);
void phys2d_edgedel(struct phys2d_edge *edge);
void phys2d_applyedge(struct phys2d_edge *edge);
void phys2d_edgeshapeapply(struct phys2d_shape *mshape, cpShape * shape);
void phys2d_dbgdrawedge(struct phys2d_edge *edge);
void phys2d_edgeaddvert(struct phys2d_edge *edge);
void edge_gui(struct phys2d_edge *edge);
void phys2d_edge_rmvert(struct phys2d_edge *edge, int index);
float phys2d_edge_moi(struct phys2d_edge *edge, float m);
void phys2d_edge_setvert(struct phys2d_edge *edge, int index, cpVect val);
void phys2d_edge_clearverts(struct phys2d_edge *edge);
void phys2d_edge_addverts(struct phys2d_edge *edge, cpVect *verts);
void phys2d_edge_set_sensor(struct phys2d_edge *edge, int sensor);
void phys2d_edge_set_enabled(struct phys2d_edge *edge, int enabled);
void phys2d_init();
void phys2d_update(float deltaT);
void phys2d_apply();
cpShape *phys2d_query_pos(cpVect pos);
int *phys2d_query_box(cpVect pos, cpVect wh);
struct phys_cbs {
struct callee begin;
struct callee separate;
};
struct shape_cb {
struct phys2d_shape *shape;
struct phys_cbs cbs;
};
void fire_hits();
void phys2d_rm_go_handlers(int go);
void phys2d_set_gravity(cpVect v);
void shape_enabled(struct phys2d_shape *shape, int enabled);
int shape_is_enabled(struct phys2d_shape *shape);
void shape_set_sensor(struct phys2d_shape *shape, int sensor);
int shape_get_sensor(struct phys2d_shape *shape);
struct rgba shape_color_s(cpShape *shape);
void shape_gui(struct phys2d_shape *shape);
void phys2d_setup_handlers(int go);
int *phys2d_query_shape(struct phys2d_shape *shape);
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);
#endif

View File

@@ -1,5 +1,4 @@
#ifndef THREEDPHYSICS_H
#define THREEDPHYSICS_H
#endif

View File

@@ -42,26 +42,26 @@ glm::vec3 ThirdPersonFollow::CalculatePosition()
glm::vec3 p1 = CalculateCenter();
glm::vec3 p2 =
XDirPosts ? GetPostsOffset(TFOR.Right(),
FloatWidths.
x) : GetExtentsOffset(TFOR.Right(),
FloatWidths.x,
TargetOffset.x,
AnchorWidths.x);
XDirPosts ? GetPostsOffset(TFOR.Right(),
FloatWidths.
x) : GetExtentsOffset(TFOR.Right(),
FloatWidths.x,
TargetOffset.x,
AnchorWidths.x);
glm::vec3 p3 =
YDirPosts ? GetPostsOffset(TFOR.Up(),
FloatWidths.
y) : GetExtentsOffset(TFOR.Up(),
FloatWidths.y,
TargetOffset.y,
AnchorWidths.y);
YDirPosts ? GetPostsOffset(TFOR.Up(),
FloatWidths.
y) : GetExtentsOffset(TFOR.Up(),
FloatWidths.y,
TargetOffset.y,
AnchorWidths.y);
glm::vec3 p4 =
ZDirPosts ? GetPostsOffset(TFOR.Back(),
FloatWidths.
z) : GetExtentsOffset(TFOR.Back(),
FloatWidths.z,
TargetOffset.z,
AnchorWidths.z);
ZDirPosts ? GetPostsOffset(TFOR.Back(),
FloatWidths.
z) : GetExtentsOffset(TFOR.Back(),
FloatWidths.z,
TargetOffset.z,
AnchorWidths.z);
return p1 + p2 + p3 + p4;
}
@@ -69,7 +69,7 @@ glm::vec3 ThirdPersonFollow::CalculatePosition()
glm::vec3 ThirdPersonFollow::CalculateCenter()
{
return Target->get_global_translation() +
TFOR.TransformDirection(Offset) + (mytransform->Back() * Distance);
TFOR.TransformDirection(Offset) + (mytransform->Back() * Distance);
}
glm::vec3 ThirdPersonFollow::
@@ -82,37 +82,37 @@ GetPostsOffset(const glm::vec3 & DirectionVector, float AnchorWidth)
glm::vec3 ThirdPersonFollow::
GetExtentsOffset(const glm::vec3 & DirectionVector, float AnchorWidth,
float TOffset, float Width)
float TOffset, float Width)
{
float negated_offset_sign = ((0 <= TOffset) - (TOffset < 0)) * -1.f;
float TotalWidth = AnchorWidth + Width;
if (glm::abs(TOffset) > TotalWidth
&& !glm::epsilonEqual(glm::abs(TOffset), TotalWidth, 0.5f))
return DirectionVector * TotalWidth * negated_offset_sign;
&& !glm::epsilonEqual(glm::abs(TOffset), TotalWidth, 0.5f))
return DirectionVector * TotalWidth * negated_offset_sign;
else {
if (glm::abs(TOffset) >= AnchorWidth)
return DirectionVector * AnchorWidth * negated_offset_sign;
else
return DirectionVector * TOffset * -1.f;
if (glm::abs(TOffset) >= AnchorWidth)
return DirectionVector * AnchorWidth * negated_offset_sign;
else
return DirectionVector * TOffset * -1.f;
}
return glm::vec3(0.f);
}
glm::vec3 ThirdPersonFollow::FrameBasedVectorLerp(const glm::vec3 & From,
const glm::vec3 & To,
const glm::vec3 & Speeds,
float Tick)
const glm::vec3 & To,
const glm::vec3 & Speeds,
float Tick)
{
// Previously "FORTransform.TransformVector(Speeds)
glm::vec3 TSpeed = glm::abs(TFOR.TransformDirection(Speeds));
glm::vec3 TOffset = glm::abs(TFOR.TransformDirection(TargetOffset));
glm::vec3 TAnchorWidths =
glm::abs(TFOR.TransformDirection(AnchorWidths));
glm::abs(TFOR.TransformDirection(AnchorWidths));
glm::vec3 TFloatWidths =
glm::abs(TFOR.TransformDirection(FloatWidths));
glm::abs(TFOR.TransformDirection(FloatWidths));
@@ -124,14 +124,14 @@ glm::vec3 ThirdPersonFollow::FrameBasedVectorLerp(const glm::vec3 & From,
float xAlpha =
glm::clamp((bUseX ? AnchorSpeed : TSpeed.x) * Tick, 0.f, 1.f);
glm::clamp((bUseX ? AnchorSpeed : TSpeed.x) * Tick, 0.f, 1.f);
float yAlpha =
glm::clamp((bUseY ? AnchorSpeed : TSpeed.y) * Tick, 0.f, 1.f);
glm::clamp((bUseY ? AnchorSpeed : TSpeed.y) * Tick, 0.f, 1.f);
float zAlpha =
glm::clamp((bUseZ ? AnchorSpeed : TSpeed.z) * Tick, 0.f, 1.f);
glm::clamp((bUseZ ? AnchorSpeed : TSpeed.z) * Tick, 0.f, 1.f);
return VectorLerpPiecewise(From, To,
glm::vec3(xAlpha, yAlpha, zAlpha));
glm::vec3(xAlpha, yAlpha, zAlpha));
}
int float_epsilon(mfloat_t a, mfloat_t b, mfloat_t e)
@@ -165,11 +165,11 @@ void ThirdPersonFollow::CalculateTargets()
// For rotation
// TODO: Check of this implementation is the same as UKismetMath FindLookAtRotation
TargetRotation =
RemoveLockedRotation(glm::quat
(mytransform->
get_global_transform()->get_origin() -
Target->
get_global_transform()->get_origin()));
RemoveLockedRotation(glm::quat
(mytransform->
get_global_transform()->get_origin() -
Target->
get_global_transform()->get_origin()));
}
follow_removelockedrot()
@@ -185,11 +185,11 @@ RemoveLockedRotation(const glm::quat & CurrentRotation)
//
NewRotator.x =
LockRoll ? mytransform->get_rotation().x : CurrentRotator.x;
LockRoll ? mytransform->get_rotation().x : CurrentRotator.x;
NewRotator.y =
LockPitch ? mytransform->get_rotation().y : CurrentRotator.y;
LockPitch ? mytransform->get_rotation().y : CurrentRotator.y;
NewRotator.z =
LockYaw ? mytransform->get_rotation().z : CurrentRotator.z;
LockYaw ? mytransform->get_rotation().z : CurrentRotator.z;
return glm::quat(NewRotator);
}
@@ -199,11 +199,11 @@ RemoveLockedRotation(const glm::quat & CurrentRotation)
void ThirdPersonFollow::CalculateTargetOffset()
{
glm::vec3 p1 =
(mytransform->Forward() * Distance) +
TFOR.TransformDirection(Offset) +
mytransform->get_global_translation();
(mytransform->Forward() * Distance) +
TFOR.TransformDirection(Offset) +
mytransform->get_global_translation();
glm::vec3 p2 =
TFOR.InverseTransformDirection(Target->get_global_translation());
TFOR.InverseTransformDirection(Target->get_global_translation());
glm::vec3 p3 = TFOR.InverseTransformDirection(p1);
TargetOffset = p2 - p3;

View File

@@ -4,22 +4,23 @@
#define THIRDPERSONFOLLOW_H
#include "transform.h"
#include "HandmadeMath.h"
struct follow {
float distance;
mfloat_t target_rot[4];
float distance;
HMM_Quat target_rot;
};
mfloat_t *follow_calccenter();
mfloat_t *follow_postoffset();
mfloat_t *extentsoffset();
mfloat_t *framebasedveclerp();
HMM_Vec3 follow_calccenter();
HMM_Vec3 follow_postoffset();
HMM_Vec3 extentsoffset();
HMM_Vec3 framebasedveclerp();
int lerpparam(float offset, float anchorwidth, float floatwidth);
mfloat_t *vec3lerp(mfloat_t from[3], mfloat_t to[3], mfloat_t a[3]);
HMM_Vec3 vec3lerp(HMM_Vec3 from, HMM_Vec3 to, HMM_Vec3 a);
void follow_calctargets();
mfloat_t *follow_removelockedrot();
HMM_Vec3 follow_removelockedrot();
void follow_targetoffset(struct follow *follow);
int float_epsilon(mfloat_t a, mfloat_t b, mfloat_t e);
int float_epsilon(float a, float b, float e);
/*
@@ -31,45 +32,45 @@ class ThirdPersonFollow {
public:
enum CameraType {
STATIONARY,
TRANSLATING,
ROTATING,
SPLINE
STATIONARY,
TRANSLATING,
ROTATING,
SPLINE
};
enum CameraTransition {
NONE,
CROSSDISSOLVE,
WIPE,
DIP
NONE,
CROSSDISSOLVE,
WIPE,
DIP
};
enum FrameOfReference {
LOCAL,
WORLD,
EXTERNAL
LOCAL,
WORLD,
EXTERNAL
};
ThirdPersonFollow() {
// Rotation
RotationSpeed = 10.0f;
LockPitch = LockYaw = LockRoll = true;
// Rotation
RotationSpeed = 10.0f;
LockPitch = LockYaw = LockRoll = true;
XDirPosts = false;
YDirPosts = false;
ZDirPosts = false;
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);
// 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;
// Frame settings
Offset = glm::vec3(0.f, 0.f, 0.f);
Distance = 10;
AnchorSpeed = 80;
AnchorSpeed = 80;
} ~ThirdPersonFollow() {
}
@@ -81,14 +82,14 @@ class ThirdPersonFollow {
void SetExternalFrame(Transform * val) {
ExternalFrame = val;
ExternalFrame = val;
}
// The target the camera "looks" at, used for calculations
Transform *Target = nullptr;
void SetTarget(Transform * val) {
Target = val;
Target = val;
}
// Offset from the target
@@ -158,25 +159,25 @@ class ThirdPersonFollow {
/// Given a direction and width, find the offsets.
glm::vec3 GetPostsOffset(const glm::vec3 & DirectionVector,
float AnchorWidth);
float AnchorWidth);
/// Given anchors, what's the anchor width?
glm::vec3 GetExtentsOffset(const glm::vec3 & DirectionVector,
float AnchorWidth, float TOffset,
float Width);
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);
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);
const glm::vec3 & To,
const glm::vec3 & Alpha);
bool GetLerpParam(const float Offst, const float AnchorWidth,
const float FloatWidth);
const float FloatWidth);
/// Set to a value that gives good clamping, smoothly. Activates when
/// the target is out of range.

View File

@@ -1,7 +1,6 @@
#include "light.h"
#include <stdbool.h>
/*
void Light::serialize(FILE * file)
{
@@ -30,20 +29,20 @@ struct mDirectionalLight *dLight = NULL;
struct mDirectionalLight *MakeDLight()
{
if (dLight != NULL) {
dLight =
(struct mDirectionalLight *)
malloc(sizeof(struct mDirectionalLight));
quat_from_euler(dLight->light.obj.transform.rotation,
dlight_init_rot);
dLight =
(struct mDirectionalLight *)
malloc(sizeof(struct mDirectionalLight));
quat_from_euler(dLight->light.obj.transform.rotation,
dlight_init_rot);
return dLight;
return dLight;
}
return dLight;
}
void dlight_prepshader(struct mDirectionalLight *light,
struct shader *shader)
struct shader *shader)
{
mfloat_t fwd[3] = { 0.f };
trans_forward(fwd, &light->light.obj.transform);
@@ -61,14 +60,14 @@ static int numLights = 0;
struct mPointLight *MakePointlight()
{
if (numLights < 4) {
struct mPointLight *light =
(struct mPointLight *) malloc(sizeof(struct mPointLight));
pointLights[numLights++] = light;
light->light.strength = 0.2f;
light->constant = 1.f;
light->linear = 0.9f;
light->quadratic = 0.032f;
return light;
struct mPointLight *light =
(struct mPointLight *) malloc(sizeof(struct mPointLight));
pointLights[numLights++] = light;
light->light.strength = 0.2f;
light->constant = 1.f;
light->linear = 0.9f;
light->quadratic = 0.032f;
return light;
}
return NULL;
@@ -82,11 +81,11 @@ static void prepstring(char *buffer, char *prepend, const char *append)
void pointlights_prepshader(struct shader *shader)
{
for (int i = 0; i < numLights; i++)
pointlight_prepshader(pointLights[i], shader, i);
pointlight_prepshader(pointLights[i], shader, i);
}
void pointlight_prepshader(struct mPointLight *light,
struct shader *shader, int num)
struct shader *shader, int num)
{
shader_use(shader);
char prepend[100] = { '\0' };
@@ -121,10 +120,10 @@ static int numSpots = 0;
struct mSpotLight *MakeSpotlight()
{
if (numSpots < 4) {
struct mSpotLight *light =
(struct mSpotLight *) malloc(sizeof(struct mSpotLight));
spotLights[numSpots++] = light;
return light;
struct mSpotLight *light =
(struct mSpotLight *) malloc(sizeof(struct mSpotLight));
spotLights[numSpots++] = light;
return light;
}
return NULL;
@@ -135,17 +134,17 @@ struct mSpotLight *MakeSpotlight()
void spotlights_prepshader(struct shader *shader)
{
for (int i = 0; i < numSpots; i++)
spotlight_prepshader(spotLights[i], shader, i);
spotlight_prepshader(spotLights[i], shader, i);
}
void spotlight_prepshader(struct mSpotLight *light, struct shader *shader,
int num)
int num)
{
mfloat_t fwd[3] = { 0.f };
trans_forward(fwd, &light->light.obj.transform);
shader_use(shader);
shader_setvec3(shader, "spotLight.position",
light->light.obj.transform.position);
light->light.obj.transform.position);
shader_setvec3(shader, "spotLight.direction", fwd);
shader_setvec3(shader, "spotLight.color", light->light.color);
shader_setfloat(shader, "spotLight.strength", light->light.strength);
@@ -165,10 +164,10 @@ void light_gui(struct mLight *light)
object_gui(&light->obj);
if (nk_tree_push(ctx, NK_TREE_NODE, "Light", NK_MINIMIZED)) {
nk_property_float(ctx, "Strength", 0.f, &light->strength, 1.f, 0.01f, 0.001f);
// ImGui::ColorEdit3("Color", &light->color[0]);
nk_checkbox_label(ctx, "Dynamic", (bool *) &light->dynamic);
nk_tree_pop(ctx);
nk_property_float(ctx, "Strength", 0.f, &light->strength, 1.f, 0.01f, 0.001f);
// ImGui::ColorEdit3("Color", &light->color[0]);
nk_checkbox_label(ctx, "Dynamic", (bool *) &light->dynamic);
nk_tree_pop(ctx);
}
}
@@ -178,10 +177,10 @@ void pointlight_gui(struct mPointLight *light)
light_gui(&light->light);
if (nk_tree_push(ctx, NK_TREE_NODE, "Point Light", NK_MINIMIZED)) {
nk_property_float(ctx, "Constant", 0.f, &light->constant, 1.f, 0.01f, 0.001f);
nk_property_float(ctx, "Linear", 0.f, &light->linear, 0.3f, 0.01f, 0.001f);
nk_property_float(ctx, "Quadratic", 0.f, &light->quadratic, 0.3f, 0.01f, 0.001f);
nk_tree_pop(ctx);
nk_property_float(ctx, "Constant", 0.f, &light->constant, 1.f, 0.01f, 0.001f);
nk_property_float(ctx, "Linear", 0.f, &light->linear, 0.3f, 0.01f, 0.001f);
nk_property_float(ctx, "Quadratic", 0.f, &light->quadratic, 0.3f, 0.01f, 0.001f);
nk_tree_pop(ctx);
}
}
@@ -191,12 +190,12 @@ void spotlight_gui(struct mSpotLight *spot)
light_gui(&spot->light);
if (nk_tree_push(ctx, NK_TREE_NODE, "Spotlight", NK_MINIMIZED)) {
nk_property_float(ctx, "Linear", 0.f, &spot->linear, 1.f, 0.01f, 0.001f);
nk_property_float(ctx, "Quadratic", 0.f, &spot->quadratic, 1.f, 0.01f, 0.001f);
nk_property_float(ctx, "Distance", 0.f, &spot->distance, 200.f, 1.f, 0.1f, 200.f);
nk_property_float(ctx, "Cutoff Degrees", 0.f, &spot->cutoff, 0.7f, 0.01f, 0.001f);
nk_property_float(ctx, "Outer Cutoff Degrees", 0.f, &spot->outerCutoff, 0.7f, 0.01f, 0.001f);
nk_tree_pop(ctx);
nk_property_float(ctx, "Linear", 0.f, &spot->linear, 1.f, 0.01f, 0.001f);
nk_property_float(ctx, "Quadratic", 0.f, &spot->quadratic, 1.f, 0.01f, 0.001f);
nk_property_float(ctx, "Distance", 0.f, &spot->distance, 200.f, 1.f, 0.1f, 200.f);
nk_property_float(ctx, "Cutoff Degrees", 0.f, &spot->cutoff, 0.7f, 0.01f, 0.001f);
nk_property_float(ctx, "Outer Cutoff Degrees", 0.f, &spot->outerCutoff, 0.7f, 0.01f, 0.001f);
nk_tree_pop(ctx);
}
}
*/

View File

@@ -4,11 +4,11 @@
#include <stdint.h>
struct mLight {
struct gameobject *go;
uint8_t color[3];
float strength;
int dynamic;
int on;
struct gameobject *go;
uint8_t color[3];
float strength;
int dynamic;
int on;
};
/*
@@ -21,7 +21,7 @@ struct mPointLight {
struct mPointLight *MakePointlight();
void pointlight_prepshader(struct mPointLight *light,
struct shader *shader, int num);
struct shader *shader, int num);
void pointlights_prepshader(struct shader *shader);
@@ -39,7 +39,7 @@ struct mSpotLight {
struct mSpotLight *MakeSpotlight();
void spotlight_gui(struct mSpotLight *light);
void spotlight_prepshader(struct mSpotLight *light, struct shader *shader,
int num);
int num);
void spotlights_prepshader(struct shader *shader);
@@ -49,7 +49,7 @@ struct mDirectionalLight {
};
void dlight_prepshader(struct mDirectionalLight *light,
struct shader *shader);
struct shader *shader);
struct mDirectionalLight *MakeDLight();
extern struct mDirectionalLight *dLight;

97
source/engine/3d/mesh.c Normal file
View File

@@ -0,0 +1,97 @@
#include "mesh.h"
#include "render.h"
#include "shader.h"
#include "texture.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void DrawMesh(struct mesh *mesh, struct shader *shader) {
// bind appropriate textures
uint32_t diffuseNr = 1;
uint32_t specularNr = 1;
uint32_t normalNr = 1;
uint32_t heightNr = 1;
// for (int i = 0; i < (mesh->te - mesh->textures); i++) {
// glActiveTexture(GL_TEXTURE0 + i); // active proper texture unit before binding
// retrieve texture number (the N in diffuse_textureN)
// char number = 0;
// TODO: malloc every single frame ... nope! Change to stack
/*char *name = malloc(sizeof(char) *(strlen(mesh->textures[i].type) + 2));*/
/*
// if (mesh->textures[i].type == TEX_DIFF)
// number = diffuseNr++;
// else if (mesh->textures[i].type == TEX_SPEC)
// number = specularNr++;
// else if (mesh->textures[i].type == TEX_NORM)
// number = normalNr++;
// else if (mesh->textures[i].type == TEX_HEIGHT)
// number = heightNr++;
*/
/*
glUniform1i(glGetUniformLocation(shader->id, name), i);
glBindTexture(GL_TEXTURE_2D, mesh->textures[i].id);
free(name);
*/
}
void DrawMeshAgain(struct mesh *mesh) {
}
void setupmesh(struct mesh *mesh) {
/*
// create buffers/arrays
glGenVertexArrays(1, &mesh->VAO);
glGenBuffers(1, &mesh->VBO);
glGenBuffers(1, &mesh->EBO);
glBindVertexArray(mesh->VAO);
// load data into vertex buffers
glBindBuffer(GL_ARRAY_BUFFER, mesh->VBO);
// The effect is that we can simply pass a pointer to the struct and it translates perfectly to vevc array which
// again translates to 3/2 floats which translates to a byte array.
glBufferData(GL_ARRAY_BUFFER,
(mesh->ve - mesh->vertices) * sizeof(struct Vertex),
&mesh->vertices[0], GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
(mesh->ie - mesh->indices) * sizeof(uint32_t),
&mesh->indices[0], GL_STATIC_DRAW);
// set the vertex attribute pointers
// vertex Positions
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(struct Vertex), NULL);
// vertex normals
glEnableVertexAttribArray(1);
// glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(struct Vertex), offsetof(struct Vertex, Normal[3]));
// vertex texture coords
glEnableVertexAttribArray(2);
// glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(struct Vertex), offsetof(struct Vertex, TexCoords[2]));
// vertex tangent
glEnableVertexAttribArray(3);
// glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(struct Vertex), offsetof(struct Vertex, Tangent[3]));
// vertex bitangent
glEnableVertexAttribArray(4);
// glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, sizeof(struct Vertex), offsetof(struct Vertex, Bitangent[3]));
// Bone ids
glEnableVertexAttribArray(5);
glVertexAttribPointer(5, 4, GL_INT, GL_FALSE, sizeof(struct Vertex), offsetof(struct Vertex,
m_BoneIDs
[MAX_BONE_INFLUENCE]));
// Weights
glEnableVertexAttribArray(6);
// glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, sizeof(struct Vertex), offsetof(struct Vertex, m_Weights));
glBindVertexArray(0);
*/
}

20
source/engine/3d/mesh.h Normal file
View File

@@ -0,0 +1,20 @@
#ifndef MESH_H
#define MESH_H
#include "sokol/sokol_gfx.h"
#include <stdint.h>
struct shader;
struct Texture;
struct mesh {
sg_bindings bind;
uint32_t face_count;
};
struct mesh *MakeMesh(struct Vertex *vertices, struct Vertex *ve, uint32_t *indices, uint32_t *ie, struct Texture *textures, struct Texture *te);
void setupmesh(struct mesh *mesh); /* Loads mesh into the GPU */
void DrawMesh(struct mesh *mesh, struct shader *shader);
void DrawMeshAgain(struct mesh *mesh); /* Draws whatever mesh was drawn last */
#endif

318
source/engine/3d/model.c Normal file
View File

@@ -0,0 +1,318 @@
#include "model.h"
#include "log.h"
#include "mesh.h"
#include "resources.h"
#include "shader.h"
#include "stb_ds.h"
#include "font.h"
#include "openglrender.h"
// #define HANDMADE_MATH_USE_TURNS
#include "HandmadeMath.h"
#include "math.h"
#include "time.h"
#define CGLTF_IMPLEMENTATION
#include <cgltf.h>
#include <stdlib.h>
#include <string.h>
#include "texture.h"
#include "sokol/sokol_gfx.h"
static struct {
char *key;
struct Texture *value;
} *modelhash = NULL;
static void processnode();
static void processmesh();
static void processtexture();
static sg_shader model_shader;
static sg_pipeline model_pipe;
void model_init() {
YughWarn("Creating model");
model_shader = sg_compile_shader("shaders/diffuse_v.glsl", "shaders/diffuse_f.glsl", &(sg_shader_desc){
.vs.uniform_blocks[0] = {
.size = sizeof(float) * 16 * 4,
.uniforms = {
[0] = {.name = "vp", .type = SG_UNIFORMTYPE_MAT4},
[1] = {.name = "model", .type = SG_UNIFORMTYPE_MAT4},
[2] = {.name = "proj", .type = SG_UNIFORMTYPE_MAT4},
[3] = {.name = "lsm", .type = SG_UNIFORMTYPE_MAT4},
}},
.fs.uniform_blocks[0] = {
.size = sizeof(float) * 3 * 5,
.uniforms = {
[0] = {.name = "point_pos", .type = SG_UNIFORMTYPE_FLOAT3},
[1] = {.name = "dir_dir", .type = SG_UNIFORMTYPE_FLOAT3},
[2] = {.name = "view_pos", .type = SG_UNIFORMTYPE_FLOAT3},
[3] = {.name = "spot_pos", .type = SG_UNIFORMTYPE_FLOAT3},
[4] = {.name = "spot_dir", .type = SG_UNIFORMTYPE_FLOAT3},
},
},
.fs.images[0] = {.name = "diffuse", .image_type = SG_IMAGETYPE_2D, .sampler_type = SG_SAMPLERTYPE_FLOAT},
.fs.images[1] = { .name = "normmap", .image_type = SG_IMAGETYPE_2D, .sampler_type = SG_SAMPLERTYPE_FLOAT},
.fs.images[2] = {.name = "shadow_map", .image_type = SG_IMAGETYPE_2D, .sampler_type = SG_SAMPLERTYPE_FLOAT},
});
model_pipe = sg_make_pipeline(&(sg_pipeline_desc){
.shader = model_shader,
.layout = {
.attrs = {
[0].format = SG_VERTEXFORMAT_FLOAT3,
[0].buffer_index = 0, /* position */
[1].format = SG_VERTEXFORMAT_USHORT2N,
[1].buffer_index = 1, /* tex coords */
[2].format = SG_VERTEXFORMAT_UINT10_N2,
[2].buffer_index = 2, /* normal */
},
},
.index_type = SG_INDEXTYPE_UINT16,
.cull_mode = SG_CULLMODE_FRONT,
.depth.write_enabled = true,
.depth.compare = SG_COMPAREFUNC_LESS_EQUAL
});
}
struct model *GetExistingModel(const char *path) {
if (!path || path[0] == '\0') return NULL;
int index = shgeti(modelhash, path);
if (index != -1) return modelhash[index].value;
return MakeModel(path);
}
cgltf_attribute *get_attr_type(cgltf_primitive p, cgltf_attribute_type t)
{
for (int i = 0; i < p.attributes_count; i++) {
if (p.attributes[i].type == t)
return &p.attributes[i];
}
return NULL;
}
unsigned short pack_short_texcoord(float c)
{
return c * USHRT_MAX;
}
uint32_t pack_int10_n2(float *norm)
{
uint32_t ni[3];
for (int i = 0; i < 3; i++) {
ni[i] = fabs(norm[i]) * 511.0 + 0.5;
ni[i] = (ni[i] > 511) ? 511 : ni[i];
ni[i] = ( norm[i] < 0.0 ) ? -ni[i] : ni[i];
}
return (ni[0] & 0x3FF) | ( (ni[1] & 0x3FF) << 10) | ( (ni[2] & 0x3FF) << 20) | ( (0 & 0x3) << 30);
}
struct model *MakeModel(const char *path) {
YughWarn("Making the model from %s.", path);
cgltf_options options = {0};
cgltf_data *data = NULL;
cgltf_result result = cgltf_parse_file(&options, path, &data);
if (!result == cgltf_result_success) {
YughError("Could not read file %s.", path);
return NULL;
}
result = cgltf_load_buffers(&options, data, path);
if (!result == cgltf_result_success) {
YughError("Could not load buffers for file %s.", path);
return NULL;
}
struct model *model = calloc(1, sizeof(*model));
/* TODO: Optimize by grouping by material. One material per draw. */
YughWarn("Model has %d materials.", data->materials_count);
float vs[65535*3];
uint16_t idxs[65535];
for (int i = 0; i < data->meshes_count; i++) {
cgltf_mesh *mesh = &data->meshes[i];
struct mesh newmesh = {0};
arrput(model->meshes,newmesh);
YughWarn("Making mesh %d. It has %d primitives.", i, mesh->primitives_count);
for (int j = 0; j < mesh->primitives_count; j++) {
cgltf_primitive primitive = mesh->primitives[j];
if (primitive.indices) {
int c = primitive.indices->count;
memcpy(idxs, cgltf_buffer_view_data(primitive.indices->buffer_view), sizeof(uint16_t) * c);
model->meshes[j].bind.index_buffer = sg_make_buffer(&(sg_buffer_desc){
.data.ptr = idxs,
.data.size = sizeof(uint16_t) * c,
.type = SG_BUFFERTYPE_INDEXBUFFER});
model->meshes[j].face_count = c;
} else {
YughWarn("Model does not have indices. Generating them.");
int c = primitive.attributes[0].data->count;
model->meshes[j].face_count = c;
for (int z = 0; z < c; z++)
idxs[z] = z;
model->meshes[j].bind.index_buffer = sg_make_buffer(&(sg_buffer_desc){
.data.ptr = idxs,
.data.size = sizeof(uint16_t) * c,
.type = SG_BUFFERTYPE_INDEXBUFFER});
}
if (primitive.material->has_pbr_metallic_roughness && primitive.material->pbr_metallic_roughness.base_color_texture.texture) {
// YughWarn("Texture is %s.", primitive.material->pbr_metallic_roughness.base_color_texture.texture->image->uri);
model->meshes[j].bind.fs_images[0] = texture_pullfromfile(primitive.material->pbr_metallic_roughness.base_color_texture.texture->image->uri)->id;
} else
model->meshes[j].bind.fs_images[0] = texture_pullfromfile("k")->id;
cgltf_texture *tex;
if (tex = primitive.material->normal_texture.texture) {
model->meshes[j].bind.fs_images[1] = texture_pullfromfile(tex->image->uri)->id;
} else
model->meshes[j].bind.fs_images[1] = texture_pullfromfile("k")->id;
model->meshes[j].bind.fs_images[2] = ddimg;
int has_norm = 0;
for (int k = 0; k < primitive.attributes_count; k++) {
cgltf_attribute attribute = primitive.attributes[k];
int n = cgltf_accessor_unpack_floats(attribute.data, NULL, 0); /* floats per element x num elements */
cgltf_accessor_unpack_floats(attribute.data, vs, n);
uint32_t *packed_norms;
unsigned short *packed_coords;
switch (attribute.type) {
case cgltf_attribute_type_position:
model->meshes[j].bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
.data.ptr = vs,
.data.size = sizeof(float) * n});
break;
case cgltf_attribute_type_normal:
has_norm = 1;
packed_norms = malloc(model->meshes[j].face_count * sizeof(uint32_t));;
for (int i = 0; i < model->meshes[j].face_count; i++)
packed_norms[i] = pack_int10_n2(vs + i*3);
model->meshes[j].bind.vertex_buffers[2] = sg_make_buffer(&(sg_buffer_desc){
.data.ptr = packed_norms,
.data.size = sizeof(uint32_t) * model->meshes[j].face_count});
free (packed_norms);
break;
case cgltf_attribute_type_tangent:
break;
case cgltf_attribute_type_texcoord:
packed_coords = malloc(model->meshes[j].face_count * 2 * sizeof(unsigned short));
for (int i = 0; i < model->meshes[j].face_count*2; i++)
packed_coords[i] = pack_short_texcoord(vs[i]);
model->meshes[j].bind.vertex_buffers[1] = sg_make_buffer(&(sg_buffer_desc){
.data.ptr = vs,
.data.size = sizeof(unsigned short) * 2 * model->meshes[j].face_count});
free(packed_coords);
break;
}
}
if (!has_norm) {
YughWarn("Model does not have normals. Generating them.");
uint32_t norms[model->meshes[j].face_count];
cgltf_attribute *pa = get_attr_type(primitive, cgltf_attribute_type_position);
int n = cgltf_accessor_unpack_floats(pa->data, NULL,0);
float ps[n];
cgltf_accessor_unpack_floats(pa->data,ps,n);
for (int i = 0, face=0; i < model->meshes[j].face_count/3; i++, face+=9) {
int o = face;
HMM_Vec3 a = {ps[o], ps[o+1],ps[o+2]};
o += 3;
HMM_Vec3 b = {ps[o], ps[o+1],ps[o+2]};
o += 3;
HMM_Vec3 c = {ps[o], ps[o+1],ps[o+2]};
HMM_Vec3 norm = HMM_NormV3(HMM_Cross(HMM_SubV3(b,a), HMM_SubV3(c,a)));
uint32_t packed_norm = pack_int10_n2(norm.Elements);
for (int j = 0; j < 3; j++)
norms[i*3+j] = packed_norm;
}
model->meshes[j].bind.vertex_buffers[2] = sg_make_buffer(&(sg_buffer_desc){
.data.ptr = norms,
.data.size = sizeof(uint32_t) * model->meshes[j].face_count
});
}
}
}
return model;
}
HMM_Vec3 eye = {50,10,5};
void draw_model(struct model *model, HMM_Mat4 amodel, HMM_Mat4 lsm) {
HMM_Mat4 proj = HMM_Perspective_RH_ZO(45, 1200.f / 720, 0.1, 10000);
HMM_Vec3 center = {0.f, 0.f, 0.f};
HMM_Vec3 up = {0.f, 1.f, 0.f};
HMM_Mat4 view = HMM_LookAt_RH(eye, center, up);
HMM_Mat4 vp = HMM_MulM4(proj, view);
HMM_Mat4 mvp = HMM_MulM4(vp, amodel);
HMM_Vec3 lp = {1, 1, 1};
HMM_Vec3 dir_dir = HMM_NormV3(HMM_SubV3(center, dirl_pos));
HMM_Mat4 m2[4];
m2[0] = view;
m2[1] = amodel;
m2[2] = proj;
m2[3] = lsm;
HMM_Vec3 f_ubo[5];
f_ubo[0] = lp;
f_ubo[1] = dir_dir;
f_ubo[2] = eye;
f_ubo[3] = eye;
f_ubo[4] = eye;
sg_apply_pipeline(model_pipe);
sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(m2));
sg_apply_uniforms(SG_SHADERSTAGE_FS, 0, SG_RANGE_REF(f_ubo));
for (int i = 0; i < arrlen(model->meshes); i++) {
sg_apply_bindings(&model->meshes[i].bind);
sg_draw(0, model->meshes[i].face_count, 1);
}
}

View File

@@ -1,15 +1,14 @@
#ifndef MODEL_H
#define MODEL_H
struct mesh;
#include "mesh.h"
#include "HandmadeMath.h"
extern HMM_Vec3 eye;
struct shader;
struct model {
struct mesh *meshes;
struct mesh *mp;
char *directory;
const char *path;
char *name;
struct mesh *meshes;
};
/* Get the model at a path, or create and return if it doesn't exist */
@@ -21,6 +20,9 @@ struct model *MakeModel(const char *path);
/* Load a model from memory into the GPU */
void loadmodel(struct model *model);
void draw_model(struct model *model, struct shader *shader);
void model_init();
void draw_model(struct model *model, HMM_Mat4 amodel, HMM_Mat4 lsm);
void draw_models(struct model *model, struct shader *shader);
#endif

126
source/engine/3d/skybox.c Normal file
View File

@@ -0,0 +1,126 @@
#include "skybox.h"
#include "camera.h"
#include "shader.h"
#include <stdlib.h>
#include <string.h>
#include "openglrender.h"
static const float skyboxVertices[216] = {
-1.0f, 1.0f, -1.0f,
-1.0f, -1.0f, -1.0f,
1.0f, -1.0f, -1.0f,
1.0f, -1.0f, -1.0f,
1.0f, 1.0f, -1.0f,
-1.0f, 1.0f, -1.0f,
-1.0f, -1.0f, 1.0f,
-1.0f, -1.0f, -1.0f,
-1.0f, 1.0f, -1.0f,
-1.0f, 1.0f, -1.0f,
-1.0f, 1.0f, 1.0f,
-1.0f, -1.0f, 1.0f,
1.0f, -1.0f, -1.0f,
1.0f, -1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
1.0f, 1.0f, -1.0f,
1.0f, -1.0f, -1.0f,
-1.0f, -1.0f, 1.0f,
-1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
1.0f, -1.0f, 1.0f,
-1.0f, -1.0f, 1.0f,
-1.0f, 1.0f, -1.0f,
1.0f, 1.0f, -1.0f,
1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
-1.0f, 1.0f, 1.0f,
-1.0f, 1.0f, -1.0f,
-1.0f, -1.0f, -1.0f,
-1.0f, -1.0f, 1.0f,
1.0f, -1.0f, -1.0f,
1.0f, -1.0f, -1.0f,
-1.0f, -1.0f, 1.0f,
1.0f, -1.0f, 1.0f};
struct mSkybox *MakeSkybox(const char *cubemap) {
/*
struct mSkybox *newskybox = malloc(sizeof(struct mSkybox));
newskybox->shader = MakeShader("skyvert.glsl", "skyfrag.glsl");
shader_compile(newskybox->shader);
glGenVertexArrays(1, &newskybox->VAO);
glGenBuffers(1, &newskybox->VBO);
glBindVertexArray(newskybox->VAO);
glBindBuffer(GL_ARRAY_BUFFER, newskybox->VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(skyboxVertices), &skyboxVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float),
(void *) 0);
shader_use(newskybox->shader);
shader_setint(newskybox->shader, "skybox", 0);
*/
/*
const char *faces[6] =
{ "right.jpg", "left.jpg", "top.jpg", "bottom.jpg", "front.jpg",
"back.jpg"
};
*/
/*
glGenTextures(1, &newskybox->id);
glBindTexture(GL_TEXTURE_CUBE_MAP, newskybox->id);
*/
/*char buf[100] = { '\0' };*/
for (int i = 0; i < 6; i++) {
/*
buf[0] = '\0';
strcat(buf, cubemap);
strcat(buf, "/");
strcat(buf, faces[i]);
IMG_Load(buf);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, 2048,
2048, 0, GL_RGB, GL_UNSIGNED_BYTE, data->pixels);
*/
}
/*
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S,
GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T,
GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R,
GL_CLAMP_TO_EDGE);
return newskybox;
*/
}
void skybox_draw(const struct mSkybox *skybox,
const struct mCamera *camera) {
/*
shader_use(skybox->shader);
mfloat_t view[16] = { 0.f };
getviewmatrix(view, camera);
shader_setmat4(skybox->shader, "skyview", view);
// skybox cube
glBindVertexArray(skybox->VAO);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_CUBE_MAP, skybox->id);
glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArray(0);
*/
}

View File

@@ -4,14 +4,14 @@
struct mCamera;
struct mSkybox {
unsigned int VAO;
unsigned int VBO;
unsigned int id;
struct shader *shader;
unsigned int VAO;
unsigned int VBO;
unsigned int id;
struct shader *shader;
};
struct mSkybox *MakeSkybox(const char *cubemap);
void skybox_draw(const struct mSkybox *skybox,
const struct mCamera *camera);
const struct mCamera *camera);
#endif

3024
source/engine/HandmadeMath.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,311 +0,0 @@
#ifndef __khrplatform_h_
#define __khrplatform_h_
/*
** Copyright (c) 2008-2018 The Khronos Group Inc.
**
** Permission is hereby granted, free of charge, to any person obtaining a
** copy of this software and/or associated documentation files (the
** "Materials"), to deal in the Materials without restriction, including
** without limitation the rights to use, copy, modify, merge, publish,
** distribute, sublicense, and/or sell copies of the Materials, and to
** permit persons to whom the Materials are furnished to do so, subject to
** the following conditions:
**
** The above copyright notice and this permission notice shall be included
** in all copies or substantial portions of the Materials.
**
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
*/
/* Khronos platform-specific types and definitions.
*
* The master copy of khrplatform.h is maintained in the Khronos EGL
* Registry repository at https://github.com/KhronosGroup/EGL-Registry
* The last semantic modification to khrplatform.h was at commit ID:
* 67a3e0864c2d75ea5287b9f3d2eb74a745936692
*
* Adopters may modify this file to suit their platform. Adopters are
* encouraged to submit platform specific modifications to the Khronos
* group so that they can be included in future versions of this file.
* Please submit changes by filing pull requests or issues on
* the EGL Registry repository linked above.
*
*
* See the Implementer's Guidelines for information about where this file
* should be located on your system and for more details of its use:
* http://www.khronos.org/registry/implementers_guide.pdf
*
* This file should be included as
* #include <KHR/khrplatform.h>
* by Khronos client API header files that use its types and defines.
*
* The types in khrplatform.h should only be used to define API-specific types.
*
* Types defined in khrplatform.h:
* khronos_int8_t signed 8 bit
* khronos_uint8_t unsigned 8 bit
* khronos_int16_t signed 16 bit
* khronos_uint16_t unsigned 16 bit
* khronos_int32_t signed 32 bit
* khronos_uint32_t unsigned 32 bit
* khronos_int64_t signed 64 bit
* khronos_uint64_t unsigned 64 bit
* khronos_intptr_t signed same number of bits as a pointer
* khronos_uintptr_t unsigned same number of bits as a pointer
* khronos_ssize_t signed size
* khronos_usize_t unsigned size
* khronos_float_t signed 32 bit floating point
* khronos_time_ns_t unsigned 64 bit time in nanoseconds
* khronos_utime_nanoseconds_t unsigned time interval or absolute time in
* nanoseconds
* khronos_stime_nanoseconds_t signed time interval in nanoseconds
* khronos_boolean_enum_t enumerated boolean type. This should
* only be used as a base type when a client API's boolean type is
* an enum. Client APIs which use an integer or other type for
* booleans cannot use this as the base type for their boolean.
*
* Tokens defined in khrplatform.h:
*
* KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values.
*
* KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.
* KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.
*
* Calling convention macros defined in this file:
* KHRONOS_APICALL
* KHRONOS_APIENTRY
* KHRONOS_APIATTRIBUTES
*
* These may be used in function prototypes as:
*
* KHRONOS_APICALL void KHRONOS_APIENTRY funcname(
* int arg1,
* int arg2) KHRONOS_APIATTRIBUTES;
*/
#if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC)
# define KHRONOS_STATIC 1
#endif
/*-------------------------------------------------------------------------
* Definition of KHRONOS_APICALL
*-------------------------------------------------------------------------
* This precedes the return type of the function in the function prototype.
*/
#if defined(KHRONOS_STATIC)
/* If the preprocessor constant KHRONOS_STATIC is defined, make the
* header compatible with static linking. */
# define KHRONOS_APICALL
#elif defined(_WIN32)
# define KHRONOS_APICALL __declspec(dllimport)
#elif defined (__SYMBIAN32__)
# define KHRONOS_APICALL IMPORT_C
#elif defined(__ANDROID__)
# define KHRONOS_APICALL __attribute__((visibility("default")))
#else
# define KHRONOS_APICALL
#endif
/*-------------------------------------------------------------------------
* Definition of KHRONOS_APIENTRY
*-------------------------------------------------------------------------
* This follows the return type of the function and precedes the function
* name in the function prototype.
*/
#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__)
/* Win32 but not WinCE */
# define KHRONOS_APIENTRY __stdcall
#else
# define KHRONOS_APIENTRY
#endif
/*-------------------------------------------------------------------------
* Definition of KHRONOS_APIATTRIBUTES
*-------------------------------------------------------------------------
* This follows the closing parenthesis of the function prototype arguments.
*/
#if defined (__ARMCC_2__)
#define KHRONOS_APIATTRIBUTES __softfp
#else
#define KHRONOS_APIATTRIBUTES
#endif
/*-------------------------------------------------------------------------
* basic type definitions
*-----------------------------------------------------------------------*/
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)
/*
* Using <stdint.h>
*/
#include <stdint.h>
typedef int32_t khronos_int32_t;
typedef uint32_t khronos_uint32_t;
typedef int64_t khronos_int64_t;
typedef uint64_t khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
/*
* To support platform where unsigned long cannot be used interchangeably with
* inptr_t (e.g. CHERI-extended ISAs), we can use the stdint.h intptr_t.
* Ideally, we could just use (u)intptr_t everywhere, but this could result in
* ABI breakage if khronos_uintptr_t is changed from unsigned long to
* unsigned long long or similar (this results in different C++ name mangling).
* To avoid changes for existing platforms, we restrict usage of intptr_t to
* platforms where the size of a pointer is larger than the size of long.
*/
#if defined(__SIZEOF_LONG__) && defined(__SIZEOF_POINTER__)
#if __SIZEOF_POINTER__ > __SIZEOF_LONG__
#define KHRONOS_USE_INTPTR_T
#endif
#endif
#elif defined(__VMS ) || defined(__sgi)
/*
* Using <inttypes.h>
*/
#include <inttypes.h>
typedef int32_t khronos_int32_t;
typedef uint32_t khronos_uint32_t;
typedef int64_t khronos_int64_t;
typedef uint64_t khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
#elif defined(_WIN32) && !defined(__SCITECH_SNAP__)
/*
* Win32
*/
typedef __int32 khronos_int32_t;
typedef unsigned __int32 khronos_uint32_t;
typedef __int64 khronos_int64_t;
typedef unsigned __int64 khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
#elif defined(__sun__) || defined(__digital__)
/*
* Sun or Digital
*/
typedef int khronos_int32_t;
typedef unsigned int khronos_uint32_t;
#if defined(__arch64__) || defined(_LP64)
typedef long int khronos_int64_t;
typedef unsigned long int khronos_uint64_t;
#else
typedef long long int khronos_int64_t;
typedef unsigned long long int khronos_uint64_t;
#endif /* __arch64__ */
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
#elif 0
/*
* Hypothetical platform with no float or int64 support
*/
typedef int khronos_int32_t;
typedef unsigned int khronos_uint32_t;
#define KHRONOS_SUPPORT_INT64 0
#define KHRONOS_SUPPORT_FLOAT 0
#else
/*
* Generic fallback
*/
#include <stdint.h>
typedef int32_t khronos_int32_t;
typedef uint32_t khronos_uint32_t;
typedef int64_t khronos_int64_t;
typedef uint64_t khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
#endif
/*
* Types that are (so far) the same on all platforms
*/
typedef signed char khronos_int8_t;
typedef unsigned char khronos_uint8_t;
typedef signed short int khronos_int16_t;
typedef unsigned short int khronos_uint16_t;
/*
* Types that differ between LLP64 and LP64 architectures - in LLP64,
* pointers are 64 bits, but 'long' is still 32 bits. Win64 appears
* to be the only LLP64 architecture in current use.
*/
#ifdef KHRONOS_USE_INTPTR_T
typedef intptr_t khronos_intptr_t;
typedef uintptr_t khronos_uintptr_t;
#elif defined(_WIN64)
typedef signed long long int khronos_intptr_t;
typedef unsigned long long int khronos_uintptr_t;
#else
typedef signed long int khronos_intptr_t;
typedef unsigned long int khronos_uintptr_t;
#endif
#if defined(_WIN64)
typedef signed long long int khronos_ssize_t;
typedef unsigned long long int khronos_usize_t;
#else
typedef signed long int khronos_ssize_t;
typedef unsigned long int khronos_usize_t;
#endif
#if KHRONOS_SUPPORT_FLOAT
/*
* Float type
*/
typedef float khronos_float_t;
#endif
#if KHRONOS_SUPPORT_INT64
/* Time types
*
* These types can be used to represent a time interval in nanoseconds or
* an absolute Unadjusted System Time. Unadjusted System Time is the number
* of nanoseconds since some arbitrary system event (e.g. since the last
* time the system booted). The Unadjusted System Time is an unsigned
* 64 bit value that wraps back to 0 every 584 years. Time intervals
* may be either signed or unsigned.
*/
typedef khronos_uint64_t khronos_utime_nanoseconds_t;
typedef khronos_int64_t khronos_stime_nanoseconds_t;
#endif
/*
* Dummy value used to pad enum types to 32 bits.
*/
#ifndef KHRONOS_MAX_ENUM
#define KHRONOS_MAX_ENUM 0x7FFFFFFF
#endif
/*
* Enumerated boolean type
*
* Values other than zero should be considered to be true. Therefore
* comparisons should not be made against KHRONOS_TRUE.
*/
typedef enum {
KHRONOS_FALSE = 0,
KHRONOS_TRUE = 1,
KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM
} khronos_boolean_enum_t;
#endif /* __khrplatform_h_ */

60
source/engine/anim.c Normal file
View File

@@ -0,0 +1,60 @@
#include "anim.h"
#include "log.h"
#include "stb_ds.h"
struct anim make_anim() {
struct anim a = {0};
a.interp = 1;
return a;
}
void free_anim(struct anim a) {
arrfree(a.frames);
}
struct anim anim_add_keyframe(struct anim a, struct keyframe key) {
arrput(a.frames, key);
return a;
}
double interval(struct keyframe a, struct keyframe b, double t) {
return (t - a.time) / (b.time - a.time);
}
double near_val(struct anim anim, double t) {
for (int i = 0; i < arrlen(anim.frames) - 1; i++) {
if (t > anim.frames[i + 1].time)
continue;
return (interval(anim.frames[i], anim.frames[i + 1], t) >= 0.5f ? anim.frames[i + 1].val : anim.frames[i].val);
}
return arrlast(anim.frames).val;
}
double lerp_val(struct anim anim, double t) {
for (int i = 0; i < arrlen(anim.frames) - 1; i++) {
if (t > anim.frames[i + 1].time)
continue;
double intv = interval(anim.frames[i], anim.frames[i + 1], t);
return ((1 - intv) * anim.frames[i].val) + (intv * anim.frames[i + 1].val);
}
return arrlast(anim.frames).val;
}
double cubic_val(struct anim anim, double t) {
return 0.0f;
}
double anim_val(struct anim anim, double t) {
if (anim.interp == 0)
return near_val(anim, t);
return lerp_val(anim, t);
}

19
source/engine/anim.h Normal file
View File

@@ -0,0 +1,19 @@
#ifndef ANIM_H
#define ANIM_H
struct keyframe {
double time;
double val;
};
struct anim {
struct keyframe *frames;
int loop;
int interp;
};
struct anim make_anim();
struct anim anim_add_keyframe(struct anim a, struct keyframe f);
double anim_val(struct anim anim, double t);
#endif

View File

@@ -3,133 +3,20 @@
#include "gameobject.h"
#include "input.h"
const float CAMERA_MINSPEED = 1.f;
const float CAMERA_MAXSPEED = 300.f;
const float CAMERA_ROTATESPEED = 6.f;
void cam_goto_object(struct mCamera *cam, struct mTransform *transform)
{
mfloat_t fwd[3] = { 0.f };
vec3_subtract(cam->transform.position, transform->position,
vec3_multiply_f(fwd, trans_forward(fwd, transform),
10.f));
void cam_goto_object(struct mCamera *cam, struct mTransform *transform) {
cam->transform.pos = HMM_SubV3(transform->pos, HMM_MulV3F(trans_forward(transform), 10.0));
}
void cam_inverse_goto(struct mCamera *cam, struct mTransform *transform)
{
mfloat_t fwd[3] = { 0.f };
vec3_add(transform->position, cam->transform.position,
vec3_multiply_f(fwd, trans_forward(fwd, &cam->transform),
10.f));
void cam_inverse_goto(struct mCamera *cam, struct mTransform *transform) {
transform->pos = HMM_AddV3(cam->transform.pos, HMM_MulV3F(trans_forward(&cam->transform), 10.0));
}
mfloat_t *getviewmatrix(mfloat_t view[16],
const struct mCamera *const camera)
HMM_Mat4 getviewmatrix(const struct mCamera *const camera)
{
mfloat_t fwd[3] = { 0.f };
mfloat_t look[3] = { 0.f };
vec3_rotate_quat(fwd, FORWARD, camera->transform.rotation);
vec3_add(look, camera->transform.position, fwd);
mat4_look_at(view, camera->transform.position, look, UP);
return view;
/*return mat4_look_at(view, ncam.transform.position,
vec3_add(look, ncam.transform.position,
trans_forward(fwd, &ncam.transform)),
UP); */
HMM_Vec3 lookvec = HMM_AddV3(camera->transform.pos, trans_forward(&camera->transform.rotation));
return HMM_LookAt_RH(camera->transform.pos, lookvec, vY);
}
void camera_2d_update(struct mCamera *camera, float deltaT)
{
static mfloat_t frame[3];
vec3_zero(frame);
if (action_down(GLFW_KEY_W))
vec3_add(frame, frame, UP);
if (action_down(GLFW_KEY_S))
vec3_add(frame, frame, DOWN);
if (action_down(GLFW_KEY_A))
vec3_add(frame, frame, LEFT);
if (action_down(GLFW_KEY_D))
vec3_add(frame, frame, RIGHT);
float speedMult = action_down(GLFW_KEY_LEFT_SHIFT) ? 2.f : 1.f;
if (!vec3_is_zero(frame)) {
vec3_normalize(frame, frame);
vec3_add(camera->transform.position, camera->transform.position,
vec3_multiply_f(frame, frame,
camera->speed * speedMult * deltaT));
}
}
/*
void camera_update(struct mCamera * camera, float mouseX, float mouseY,
const uint8_t * keystate, int32_t mouseWheelY,
float deltaTime)
{
// if (SDL_GetRelativeMouseMode()) vec3_zero(camera->frame_move);
static mfloat_t holdvec[VEC3_SIZE];
vec3_zero(camera->frame_move);
if (currentKeystates[SDL_SCANCODE_W])
vec3_add(camera->frame_move, camera->frame_move,
trans_forward(holdvec, &camera->transform));
if (currentKeystates[SDL_SCANCODE_S])
vec3_subtract(camera->frame_move, camera->frame_move,
trans_forward(holdvec, &camera->transform));
if (currentKeystates[SDL_SCANCODE_A])
vec3_subtract(camera->frame_move, camera->frame_move,
trans_right(holdvec, &camera->transform));
if (currentKeystates[SDL_SCANCODE_D])
vec3_add(camera->frame_move, camera->frame_move,
trans_right(holdvec, &camera->transform));
if (currentKeystates[SDL_SCANCODE_E])
vec3_add(camera->frame_move, camera->frame_move,
trans_up(holdvec, &camera->transform));
if (currentKeystates[SDL_SCANCODE_Q])
vec3_subtract(camera->frame_move, camera->frame_move,
trans_up(holdvec, &camera->transform));
camera->speedMult = currentKeystates[SDL_SCANCODE_LSHIFT] ? 2.f : 1.f;
if (!vec3_is_zero(camera->frame_move)) {
vec3_normalize(camera->frame_move, camera->frame_move);
vec3_add(camera->transform.position, camera->transform.position,
vec3_multiply_f(camera->frame_move, camera->frame_move,
camera->speed * camera->speedMult *
deltaTime));
}
// Adjust speed based on mouse wheel
camera->speed =
clampf(camera->speed + mouseWheelY, CAMERA_MINSPEED,
CAMERA_MAXSPEED);
// TODO: Handle this as additive quaternions
camera->yaw -= mouseX * CAMERA_ROTATESPEED * deltaTime;
camera->pitch -= mouseY * CAMERA_ROTATESPEED * deltaTime;
if (camera->pitch > 89.f)
camera->pitch = 89.f;
if (camera->pitch < -89.f)
camera->pitch = -89.f;
mfloat_t qyaw[4] = {0.f};
mfloat_t qpitch[4] = {0.f};
quat_from_axis_angle(qyaw, UP, camera->yaw);
quat_from_axis_angle(qpitch, RIGHT, camera->pitch);
quat_multiply(camera->transform.rotation, qyaw, qpitch);
}
*/

View File

@@ -8,16 +8,15 @@ extern const float CAMERA_MAXSPEED;
extern const float CAMERA_ROTATESPEED;
struct mCamera {
struct mTransform transform;
float speed;
float speedMult;
mfloat_t frame_move[VEC3_SIZE];
struct mTransform transform;
float speed;
float speedMult;
HMM_Vec3 frame_move;
};
void camera_2d_update(struct mCamera *camera, float deltaT);
mfloat_t *getviewmatrix(mfloat_t view[MAT4_SIZE],
const struct mCamera *const camera);
HMM_Mat4 getviewmatrix(const struct mCamera *const camera);
void cam_goto_object(struct mCamera *cam, struct mTransform *transform);
void cam_inverse_goto(struct mCamera *cam, struct mTransform *transform);

View File

@@ -1,21 +1,13 @@
#ifndef CONFIG_H
#define CONFIG_H
#define MAXPATH 256 /* 255 chars + null */
#define MAXPATH 256 /* 255 chars + null */
#define MAXNAME 50
#define SCREEN_WIDTH 1280
#define SCREEN_HEIGHT 720
#define PI 3.14159265358979323846264338327950288f
#define DEG2RADS 0.0174532925199432957692369076848861271344287188854172545609719144f
#define RAD2DEGS 57.2958f
#define MSAA_SAMPLES 2
#endif

View File

@@ -1,198 +1,163 @@
#include "datastream.h"
#include "render.h"
#include "config.h"
#include "shader.h"
#include "resources.h"
#include "sound.h"
#include <stdbool.h>
#include "log.h"
#include "texture.h"
#include <stdlib.h>
#include "mix.h"
#include "limits.h"
#include "dsp.h"
#include "iir.h"
#include "limits.h"
#include "log.h"
#include "mix.h"
#include "render.h"
#include "resources.h"
#include "shader.h"
#include "sound.h"
#include "texture.h"
#include <stdbool.h>
#include <stdlib.h>
#include "font.h"
#include "openglrender.h"
struct shader *vid_shader;
#include "sokol/sokol_gfx.h"
static void ds_update_texture(uint32_t unit, uint32_t texture, plm_plane_t * plane)
{
glActiveTexture(unit);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, plane->width, plane->height, 0, GL_RED, GL_UNSIGNED_BYTE, plane->data);
sg_shader vid_shader;
sg_pipeline vid_pipeline;
sg_bindings vid_bind;
static void render_frame(plm_t *mpeg, plm_frame_t *frame, void *user) {
struct datastream *ds = user;
uint8_t rgb[frame->height*frame->width*4];
plm_frame_to_rgba(frame, rgb, frame->width*4);
sg_image_data imgd;
sg_range ir = {
.ptr = rgb,
.size = frame->height*frame->width*4*sizeof(uint8_t)
};
imgd.subimage[0][0] = ir;
sg_update_image(ds->img, &imgd);
}
static void render_frame(plm_t * mpeg, plm_frame_t * frame, void *user)
{
struct datastream *ds = user;
shader_use(ds->shader);
ds_update_texture(GL_TEXTURE0, ds->texture_y, &frame->y);
ds_update_texture(GL_TEXTURE1, ds->texture_cb, &frame->cb);
ds_update_texture(GL_TEXTURE2, ds->texture_cr, &frame->cr);
static void render_audio(plm_t *mpeg, plm_samples_t *samples, void *user) {
struct datastream *ds = user;
short t;
for (int i = 0; i < samples->count * CHANNELS; i++) {
t = (short)(samples->interleaved[i] * SHRT_MAX);
// cbuf_push(ds->astream->buf, t * 5);
}
}
static void render_audio(plm_t * mpeg, plm_samples_t * samples, void *user)
{
struct datastream *ds = user;
short t;
void ds_openvideo(struct datastream *ds, const char *video, const char *adriver) {
// ds_stop(ds);
char buf[MAXPATH] = {'\0'};
sprintf(buf, "%s%s", "video/", video);
ds->plm = plm_create_with_filename(buf);
for (int i = 0; i < samples->count * CHANNELS; i++) {
t = (short)(samples->interleaved[i] * SHRT_MAX);
cbuf_push(ds->astream->buf, t*5);
}
if (!ds->plm) {
YughLog(0, 0, "Couldn't open %s", video);
}
ds->img = sg_make_image(&(sg_image_desc){
.width = plm_get_width(ds->plm),
.height = plm_get_height(ds->plm)
});
YughLog(0, 0, "Opened %s - framerate: %f, samplerate: %d, audio streams: %i, duration: %f",
video,
plm_get_framerate(ds->plm),
plm_get_samplerate(ds->plm),
plm_get_num_audio_streams(ds->plm),
plm_get_duration(ds->plm));
ds->astream = soundstream_make();
struct dsp_filter astream_filter;
astream_filter.data = &ds->astream;
astream_filter.filter = soundstream_fillbuf;
// struct dsp_filter lpf = lpf_make(8, 10000);
struct dsp_filter lpf = lpf_make(1, 200);
struct dsp_iir *iir = lpf.data;
iir->in = astream_filter;
struct dsp_filter hpf = hpf_make(1, 2000);
struct dsp_iir *hiir = hpf.data;
hiir->in = astream_filter;
/*
struct dsp_filter llpf = lp_fir_make(20);
struct dsp_fir *fir = llpf.data;
fir->in = astream_filter;
*/
// first_free_bus(astream_filter);
plm_set_video_decode_callback(ds->plm, render_frame, ds);
plm_set_audio_decode_callback(ds->plm, render_audio, ds);
plm_set_loop(ds->plm, false);
plm_set_audio_enabled(ds->plm, true);
plm_set_audio_stream(ds->plm, 0);
// Adjust the audio lead time according to the audio_spec buffer size
plm_set_audio_lead_time(ds->plm, BUF_FRAMES / SAMPLERATE);
ds->playing = true;
}
struct Texture *ds_maketexture(struct datastream *ds)
{
struct Texture *new = malloc(sizeof(*new));
new->id = ds->texture_cb;
new->width = 500;
new->height = 500;
return new;
struct datastream *MakeDatastream() {
vid_shader = sg_compile_shader("shaders/videovert.glsl", "shaders/videofrag.glsl", &(sg_shader_desc){
.fs.images[0] = {
.name = "video",
.image_type = SG_IMAGETYPE_2D,
.sampler_type = SG_SAMPLERTYPE_FLOAT
}});
}
void ds_openvideo(struct datastream *ds, const char *video, const char *adriver)
{
// ds_stop(ds);
char buf[MAXPATH] = {'\0'};
sprintf(buf, "%s%s", "video/", video);
ds->plm = plm_create_with_filename(buf);
if (!ds->plm) {
YughLog(0, 0, "Couldn't open %s", video);
}
YughLog(0, 0, "Opened %s - framerate: %f, samplerate: %d, audio streams: %i, duration: %f",
video,
plm_get_framerate(ds->plm),
plm_get_samplerate(ds->plm),
plm_get_num_audio_streams(ds->plm),
plm_get_duration(ds->plm)
);
ds->astream = soundstream_make();
struct dsp_filter astream_filter;
astream_filter.data = &ds->astream;
astream_filter.filter = soundstream_fillbuf;
//struct dsp_filter lpf = lpf_make(8, 10000);
struct dsp_filter lpf = lpf_make(1, 200);
struct dsp_iir *iir = lpf.data;
iir->in = astream_filter;
struct dsp_filter hpf = hpf_make(1, 2000);
struct dsp_iir *hiir = hpf.data;
hiir->in = astream_filter;
/*
struct dsp_filter llpf = lp_fir_make(20);
struct dsp_fir *fir = llpf.data;
fir->in = astream_filter;
*/
//first_free_bus(astream_filter);
plm_set_video_decode_callback(ds->plm, render_frame, ds);
plm_set_audio_decode_callback(ds->plm, render_audio, ds);
plm_set_loop(ds->plm, false);
plm_set_audio_enabled(ds->plm, true);
plm_set_audio_stream(ds->plm, 0);
// Adjust the audio lead time according to the audio_spec buffer size
plm_set_audio_lead_time(ds->plm, 4096/48000);
ds->playing = true;
void ds_advance(struct datastream *ds, double s) {
if (ds->playing) {
plm_decode(ds->plm, s);
}
}
struct datastream *MakeDatastream()
{
struct datastream *newds = malloc(sizeof(*newds));
if (!vid_shader) vid_shader = MakeShader("videovert.glsl", "videofrag.glsl");
newds->shader = vid_shader;
shader_use(newds->shader);
glGenTextures(1, &newds->texture_y);
glBindTexture(GL_TEXTURE_2D, newds->texture_y);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
shader_setint(newds->shader, "texture_y", 0);
glGenTextures(1, &newds->texture_cb);
glBindTexture(GL_TEXTURE_2D, newds->texture_cb);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
shader_setint(newds->shader, "texture_cb", 1);
glGenTextures(1, &newds->texture_cr);
glBindTexture(GL_TEXTURE_2D, newds->texture_cr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
shader_setint(newds->shader, "texture_cr", 2);
return newds;
void ds_seek(struct datastream *ds, double time) {
// clear_raw(ds->audio_device);
plm_seek(ds->plm, time, false);
}
void ds_advance(struct datastream *ds, double s)
{
if (ds->playing) {
plm_decode(ds->plm, s);
}
void ds_advanceframes(struct datastream *ds, int frames) {
for (int i = 0; i < frames; i++) {
plm_frame_t *frame = plm_decode_video(ds->plm);
render_frame(ds->plm, frame, ds);
}
}
void ds_seek(struct datastream *ds, double time)
{
//clear_raw(ds->audio_device);
plm_seek(ds->plm, time, false);
void ds_pause(struct datastream *ds) {
ds->playing = false;
}
void ds_advanceframes(struct datastream *ds, int frames)
{
for (int i = 0; i < frames; i++) {
plm_frame_t *frame = plm_decode_video(ds->plm);
render_frame(ds->plm, frame, ds);
}
}
void ds_pause(struct datastream *ds)
{
ds->playing = false;
}
void ds_stop(struct datastream *ds)
{
if (ds->plm != NULL) {
plm_destroy(ds->plm);
ds->plm = NULL;
}
if (ds->audio_device)
close_audio_device(ds->audio_device);
ds->playing = false;
void ds_stop(struct datastream *ds) {
if (ds->plm != NULL) {
plm_destroy(ds->plm);
ds->plm = NULL;
}
if (ds->audio_device)
close_audio_device(ds->audio_device);
ds->playing = false;
}
// TODO: Must be a better way
int ds_videodone(struct datastream *ds)
{
return (ds->plm == NULL)
|| plm_get_time(ds->plm) >= plm_get_duration(ds->plm);
int ds_videodone(struct datastream *ds) {
return (ds->plm == NULL) || plm_get_time(ds->plm) >= plm_get_duration(ds->plm);
}
double ds_remainingtime(struct datastream *ds)
{
if (ds->plm != NULL)
return plm_get_duration(ds->plm) - plm_get_time(ds->plm);
else
return 0.f;
double ds_remainingtime(struct datastream *ds) {
if (ds->plm != NULL)
return plm_get_duration(ds->plm) - plm_get_time(ds->plm);
else
return 0.f;
}
double ds_length(struct datastream *ds)
{
return plm_get_duration(ds->plm);
double ds_length(struct datastream *ds) {
return plm_get_duration(ds->plm);
}

View File

@@ -1,30 +1,29 @@
#ifndef DATASTREAM_H
#define DATASTREAM_H
#include <stdint.h>
#include <pl_mpeg.h>
#include <stdint.h>
#include "sokol/sokol_gfx.h"
struct soundstream;
struct datastream {
plm_t *plm;
struct shader *shader;
double last_time;
int playing;
int audio_device;
uint32_t texture_y;
uint32_t texture_cb;
uint32_t texture_cr;
struct soundstream *astream;
plm_t *plm;
double last_time;
int playing;
int audio_device;
sg_image img;
int width;
int height;
struct soundstream *astream;
};
struct Texture;
extern struct shader *vid_shader;
struct datastream *MakeDatastream();
void ds_openvideo(struct datastream *ds, const char *path, const char *adriver);
struct Texture *ds_maketexture(struct datastream*);
struct Texture *ds_maketexture(struct datastream *);
void ds_advance(struct datastream *ds, double);
void ds_seek(struct datastream *ds, double);
void ds_advanceframes(struct datastream *ds, int frames);

View File

@@ -1,9 +1,8 @@
#ifndef DEBUG_GUI_H
#define DEBUG_GUI_H
#define static_assert(pred) switch(0){case 0:case pred:;}
extern unsigned long long triCount;
void resetTriangles();
#endif

View File

@@ -0,0 +1,652 @@
#include "debugdraw.h"
#include "openglrender.h"
#include "render.h"
#include "yugine.h"
#include "shader.h"
#include "log.h"
#include <assert.h>
#include "debug.h"
#include "window.h"
#include "2dphysics.h"
#include "stb_ds.h"
#include "sokol/sokol_gfx.h"
#define PAR_STREAMLINES_IMPLEMENTATION
#include "par/par_streamlines.h"
#include "font.h"
#define v_amt 5000
static sg_shader point_shader;
static sg_pipeline point_pipe;
static sg_bindings point_bind;
struct point_vertex {
cpVect pos;
struct rgba color;
float radius;
};
static int point_c = 0;
static int point_sc = 0;
static struct point_vertex point_b[v_amt];
static sg_shader line_shader;
static sg_pipeline line_pipe;
static sg_bindings line_bind;
struct line_vert {
cpVect pos;
float dist;
struct rgba color;
float seg_len;
float seg_speed;
};
static int line_c = 0;
static int line_v = 0;
static int line_sc = 0;
static int line_sv = 0;
static struct line_vert line_b[v_amt];
static uint16_t line_bi[v_amt];
static sg_pipeline grid_pipe;
static sg_bindings grid_bind;
static sg_shader grid_shader;
static int grid_c = 0;
static sg_pipeline poly_pipe;
static sg_bindings poly_bind;
static sg_shader poly_shader;
static int poly_c = 0;
static int poly_v = 0;
static int poly_sc = 0;
static int poly_sv = 0;
struct poly_vertex {
cpVect pos;
float uv[2];
struct rgba color;
};
static struct poly_vertex poly_b[v_amt];
static uint32_t poly_bi[v_amt];
static sg_pipeline circle_pipe;
static sg_bindings circle_bind;
static sg_shader csg;
static int circle_count = 0;
static int circle_sc = 0;
struct circle_vertex {
cpVect pos;
float radius;
struct rgba color;
float segsize;
float fill;
};
static struct circle_vertex circle_b[v_amt];
void debug_flush(HMM_Mat4 *view)
{
if (poly_c != 0) {
sg_apply_pipeline(poly_pipe);
sg_apply_bindings(&poly_bind);
sg_apply_uniforms(SG_SHADERSTAGE_VS,0,SG_RANGE_REF(*view));
sg_append_buffer(poly_bind.vertex_buffers[0], &(sg_range){
.ptr = poly_b, .size = sizeof(struct poly_vertex)*poly_v});
sg_append_buffer(poly_bind.index_buffer, &(sg_range){
.ptr = poly_bi, .size = sizeof(uint32_t)*poly_c});
sg_draw(poly_sc,poly_c,1);
}
if (point_c != 0) {
sg_apply_pipeline(point_pipe);
sg_apply_bindings(&point_bind);
sg_apply_uniforms(SG_SHADERSTAGE_VS,0,SG_RANGE_REF(*view));
sg_append_buffer(point_bind.vertex_buffers[0], &(sg_range){
.ptr = point_b,
.size = sizeof(struct point_vertex)*point_c});
sg_draw(point_sc,point_c,1);
}
if (line_c != 0) {
sg_apply_pipeline(line_pipe);
sg_apply_bindings(&line_bind);
sg_apply_uniforms(SG_SHADERSTAGE_VS,0,SG_RANGE_REF(*view));
float time = lastTick;
sg_range tr = {
.ptr = &time,
.size = sizeof(float)
};
sg_apply_uniforms(SG_SHADERSTAGE_FS,0,&tr);
sg_append_buffer(line_bind.vertex_buffers[0], &(sg_range){
.ptr = line_b, .size = sizeof(struct line_vert)*line_v});
sg_append_buffer(line_bind.index_buffer, &(sg_range){
.ptr = line_bi, .size = sizeof(uint16_t)*line_c});
sg_draw(line_sc,line_c,1);
}
if (circle_count != 0) {
sg_apply_pipeline(circle_pipe);
sg_apply_bindings(&circle_bind);
sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(*view));
sg_append_buffer(circle_bind.vertex_buffers[0], &(sg_range){
.ptr = circle_b,
.size = sizeof(struct circle_vertex)*circle_count
});
sg_draw(circle_sc,4,circle_count);
}
}
void debug_nextpass()
{
point_sc = point_c;
point_c = 0;
circle_sc = circle_count;
circle_count = 0;
line_sv = line_v;
line_v = 0;
line_sc = line_c;
line_c = 0;
poly_sc = poly_c;
poly_c = 0;
poly_sv = poly_v;
poly_v = 0;
}
void debug_newframe()
{
point_sc = 0;
point_c = 0;
circle_sc = circle_count = line_sv = line_v = line_sc = line_c = poly_sc = poly_c = 0;
poly_sv = poly_v = 0;
}
static sg_shader_uniform_block_desc projection_ubo = {
.size = sizeof(projection),
.uniforms = {
[0] = { .name = "proj", .type = SG_UNIFORMTYPE_MAT4 },
}
};
static sg_shader_uniform_block_desc time_ubo = {
.size = sizeof(float),
.uniforms = {
[0] = { .name = "time", .type = SG_UNIFORMTYPE_FLOAT },
}
};
void debugdraw_init()
{
point_shader = sg_compile_shader("shaders/point_v.glsl", "shaders/point_f.glsl", &(sg_shader_desc){
.vs.uniform_blocks[0] = projection_ubo
});
point_pipe = sg_make_pipeline(&(sg_pipeline_desc){
.shader = point_shader,
.layout = {
.attrs = {
[0].format = SG_VERTEXFORMAT_FLOAT2, /* pos */
[1].format = SG_VERTEXFORMAT_UBYTE4N, /* color */
[2].format = SG_VERTEXFORMAT_FLOAT /* radius */
}
},
.primitive_type = SG_PRIMITIVETYPE_POINTS,
.colors[0].blend = blend_trans
});
point_bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
.size = sizeof(struct point_vertex)*v_amt,
.usage = SG_USAGE_STREAM
});
line_shader = sg_compile_shader("shaders/linevert.glsl", "shaders/linefrag.glsl", &(sg_shader_desc){
.vs.uniform_blocks[0] = projection_ubo,
.fs.uniform_blocks[0] = time_ubo
});
line_pipe = sg_make_pipeline(&(sg_pipeline_desc){
.shader = line_shader,
.layout = {
.attrs = {
[0].format = SG_VERTEXFORMAT_FLOAT2, /* pos */
[1].format = SG_VERTEXFORMAT_FLOAT, /* dist */
[2].format = SG_VERTEXFORMAT_UBYTE4N, /* color */
[3].format = SG_VERTEXFORMAT_FLOAT, /* seg length */
[4].format = SG_VERTEXFORMAT_FLOAT /* dashed line speed */
}
},
.primitive_type = SG_PRIMITIVETYPE_LINES,
.index_type = SG_INDEXTYPE_UINT16,
.colors[0].blend = blend_trans
});
line_bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
.size = sizeof(struct line_vert)*v_amt,
.usage = SG_USAGE_STREAM
});
line_bind.index_buffer = sg_make_buffer(&(sg_buffer_desc){
.size = sizeof(uint16_t)*v_amt,
.usage = SG_USAGE_STREAM,
.type = SG_BUFFERTYPE_INDEXBUFFER
});
csg = sg_compile_shader("shaders/circlevert.glsl", "shaders/circlefrag.glsl", &(sg_shader_desc){
.vs.uniform_blocks[0] = projection_ubo,
});
circle_pipe = sg_make_pipeline(&(sg_pipeline_desc){
.shader = csg,
.layout = {
.attrs = {
[0].format = SG_VERTEXFORMAT_FLOAT2,
[0].buffer_index = 1,
[1].format = SG_VERTEXFORMAT_FLOAT2,
[2].format = SG_VERTEXFORMAT_FLOAT,
[3].format = SG_VERTEXFORMAT_UBYTE4N,
[4].format = SG_VERTEXFORMAT_FLOAT,
[5].format = SG_VERTEXFORMAT_FLOAT
},
.buffers[0].step_func = SG_VERTEXSTEP_PER_INSTANCE,
},
.primitive_type = SG_PRIMITIVETYPE_TRIANGLE_STRIP,
.cull_mode = SG_CULLMODE_BACK,
.colors[0].blend = blend_trans,
.label = "circle pipeline"
});
circle_bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
.size = sizeof(struct circle_vertex)*v_amt,
.usage = SG_USAGE_STREAM,
});
float circleverts[8] = {
-1,-1,
-1,1,
1,-1,
1,1
};
circle_bind.vertex_buffers[1] = sg_make_buffer(&(sg_buffer_desc){
.data = SG_RANGE(circleverts),
.usage = SG_USAGE_IMMUTABLE,
});
grid_shader = sg_compile_shader("shaders/gridvert.glsl", "shaders/gridfrag.glsl", &(sg_shader_desc){
.vs.uniform_blocks[0] = projection_ubo,
.vs.uniform_blocks[1] = {
.size = sizeof(float)*2,
.uniforms = { [0] = { .name = "offset", .type = SG_UNIFORMTYPE_FLOAT2 } } },
.fs.uniform_blocks[0] = {
.size = sizeof(float)*6,
.uniforms = {
[0] = { .name = "thickness", .type = SG_UNIFORMTYPE_FLOAT },
[1] = { .name = "span", .type = SG_UNIFORMTYPE_FLOAT },
[2] = { .name = "color", .type = SG_UNIFORMTYPE_FLOAT4 },
}
},
});
grid_pipe = sg_make_pipeline(&(sg_pipeline_desc){
.shader = grid_shader,
.layout = {
.attrs = {
[0].format = SG_VERTEXFORMAT_FLOAT2, /* pos */
}
},
.primitive_type = SG_PRIMITIVETYPE_TRIANGLE_STRIP,
// .cull_mode = sg_cullmode_back,
.label = "grid pipeline",
.colors[0].blend = blend_trans,
});
grid_bind.vertex_buffers[0] = circle_bind.vertex_buffers[1];
poly_shader = sg_compile_shader("shaders/poly_v.glsl", "shaders/poly_f.glsl", &(sg_shader_desc){
.vs.uniform_blocks[0] = projection_ubo
});
poly_pipe = sg_make_pipeline(&(sg_pipeline_desc){
.shader = poly_shader,
.layout = {
.attrs = { [0].format = SG_VERTEXFORMAT_FLOAT2, /* pos */
[1].format = SG_VERTEXFORMAT_FLOAT2, /* uv */
[2].format = SG_VERTEXFORMAT_UBYTE4N /* color rgba */
}
},
.index_type = SG_INDEXTYPE_UINT32,
.colors[0].blend = blend_trans,
});
poly_bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
.size = sizeof(struct poly_vertex)*v_amt,
.usage = SG_USAGE_STREAM,
.type = SG_BUFFERTYPE_VERTEXBUFFER,
});
poly_bind.index_buffer = sg_make_buffer(&(sg_buffer_desc){
.size = sizeof(uint32_t)*6*v_amt,
.usage = SG_USAGE_STREAM,
.type = SG_BUFFERTYPE_INDEXBUFFER
});
}
void draw_line(cpVect *a_points, int a_n, struct rgba color, float seg_len, int closed, float seg_speed)
{
if (a_n < 2) return;
seg_speed = 1;
int n = closed ? a_n+1 : a_n;
cpVect points[n];
memcpy(points, a_points, sizeof(cpVect)*n);
if (closed)
points[n-1] = a_points[0];
struct line_vert v[n];
float dist = 0;
for (int i = 0; i < n-1; i++) {
v[i].pos = points[i];
v[i].dist = dist;
v[i].color = color;
v[i].seg_len = seg_len;
v[i].seg_speed = seg_speed;
dist += cpvdist(points[i], points[i+1]);
}
v[n-1].pos = points[n-1];
v[n-1].dist = dist;
v[n-1].color = color;
v[n-1].seg_len = seg_len;
v[n-1].seg_speed = seg_speed;
int i_c = (n-1)*2;
uint16_t idxs[i_c];
for (int i = 0, d = 0; i < n-1; i++, d+=2) {
idxs[d] = i + line_v + line_sv;
idxs[d+1] = i+1 + line_v + line_sv;
}
sg_range vr = {
.ptr = v,
.size = sizeof(struct line_vert)*n
};
sg_range ir = {
.ptr = idxs,
.size = sizeof(uint16_t)*i_c
};
memcpy(line_b+line_v, v, sizeof(struct line_vert)*n);
memcpy(line_bi+line_c, idxs, sizeof(uint16_t)*i_c);
line_c += i_c;
line_v += n;
}
cpVect center_of_vects(cpVect *v, int n)
{
cpVect c;
for (int i = 0; i < n; i++) {
c.x += v[i].x;
c.y += v[i].y;
}
c.x /= n;
c.y /= n;
return c;
}
float vecs2m(cpVect a, cpVect b)
{
return (b.y-a.y)/(b.x-a.x);
}
cpVect inflatepoint(cpVect a, cpVect b, cpVect c, float d)
{
cpVect ba = cpvnormalize(cpvsub(a,b));
cpVect bc = cpvnormalize(cpvsub(c,b));
cpVect avg = cpvadd(ba, bc);
avg = cpvmult(avg, 0.5);
float dot = cpvdot(ba, bc);
dot /= cpvlength(ba);
dot /= cpvlength(bc);
float mid = acos(dot)/2;
avg = cpvnormalize(avg);
return cpvadd(b, cpvmult(avg, d/sin(mid)));
}
void inflatepoints(cpVect *r, cpVect *p, float d, int n)
{
if (d == 0) {
for (int i = 0; i < n; i++)
r[i] = p[i];
return;
}
if (cpveql(p[0], p[n-1])) {
r[0] = inflatepoint(p[n-2],p[0],p[1],d);
r[n-1] = r[0];
} else {
cpVect outdir = cpvmult(cpvnormalize(cpvsub(p[0],p[1])),fabs(d));
cpVect perp;
if (d > 0)
perp = cpvperp(outdir);
else
perp = cpvrperp(outdir);
r[0] = cpvadd(p[0],cpvadd(outdir,perp));
outdir = cpvmult(cpvnormalize(cpvsub(p[n-1],p[n-2])),fabs(d));
if (d > 0)
perp = cpvrperp(outdir);
else
perp = cpvperp(outdir);
r[n-1] = cpvadd(p[n-1],cpvadd(outdir,perp));
}
for (int i = 0; i < n-2; i++)
r[i+1] = inflatepoint(p[i],p[i+1],p[i+2], d);
}
void draw_edge(cpVect *points, int n, struct rgba color, int thickness, int closed, int flags, struct rgba line_color, float line_seg)
{
static_assert(sizeof(cpVect) == 2*sizeof(float));
if (thickness == 0) {
thickness = 1;
}
/* todo: should be dashed, and filled. use a texture. */
/* draw polygon outline */
if (cpveql(points[0], points[n-1])) {
closed = true;
n--;
}
parsl_position par_v[n];
for (int i = 0; i < n; i++) {
par_v[i].x = points[i].x;
par_v[i].y = points[i].y;
}
uint16_t spine_lens[] = {n};
parsl_context *par_ctx = parsl_create_context((parsl_config){
.thickness = thickness,
.flags = PARSL_FLAG_ANNOTATIONS,
.u_mode = PAR_U_MODE_DISTANCE,
});
parsl_mesh *mesh = parsl_mesh_from_lines(par_ctx, (parsl_spine_list){
.num_vertices = n,
.num_spines = 1,
.vertices = par_v,
.spine_lengths = spine_lens,
.closed = closed
});
for (int i = 0; i < mesh->num_triangles*3; i++)
mesh->triangle_indices[i] += (poly_v+poly_sv);
struct poly_vertex vertices[mesh->num_vertices];
for (int i = 0; i < mesh->num_vertices; i++) {
vertices[i].pos = (cpVect){ .x = mesh->positions[i].x, .y = mesh->positions[i].y };
vertices[i].uv[0] = mesh->annotations[i].u_along_curve;
vertices[i].uv[1] = mesh->annotations[i].v_across_curve;
vertices[i].color = color;
}
memcpy(poly_b+poly_v, vertices, sizeof(struct poly_vertex)*mesh->num_vertices);
memcpy(poly_bi+poly_c, mesh->triangle_indices, sizeof(uint32_t)*mesh->num_triangles*3);
poly_c += mesh->num_triangles*3;
poly_v += mesh->num_vertices;
parsl_destroy_context(par_ctx);
/* Now drawing the line outlines */
if (thickness == 1) {
draw_line(points,n,line_color,line_seg, 0, 0);
} else {
/* Draw inside and outside lines */
cpVect in_p[n];
cpVect out_p[n];
for (int i = 0, v = 0; i < n*2+1; i+=2, v++)
in_p[v] = vertices[i].pos;
for (int i = 1, v = 0; i < n*2; i+=2,v++)
out_p[v] = vertices[i].pos;
draw_line(in_p,n,line_color,line_seg,1,0);
draw_line(out_p,n,line_color,line_seg,1,0);
}
}
void draw_circle(cpVect pos, float radius, float pixels, struct rgba color, float seg)
{
struct circle_vertex cv;
cv.pos = pos;
cv.radius = radius;
cv.color = color;
cv.segsize = seg/radius;
cv.fill = pixels/radius;
memcpy(circle_b+circle_count, &cv, sizeof(struct circle_vertex));
circle_count++;
}
void draw_box(struct cpVect c, struct cpVect wh, struct rgba color)
{
float hw = wh.x / 2.f;
float hh = wh.y / 2.f;
cpVect verts[4] = {
{ .x = c.x-hw, .y = c.y-hh },
{ .x = c.x+hw, .y = c.y-hh },
{ .x = c.x+hw, .y = c.y+hh },
{ .x = c.x-hw, .y = c.y+hh }
};
draw_poly(verts, 4, color);
}
void draw_arrow(struct cpVect start, struct cpVect end, struct rgba color, int capsize)
{
cpVect points[2] = {start, end};
draw_line(points, 2, color, 0, 0,0);
draw_cppoint(end, capsize, color);
}
void draw_grid(int width, int span, struct rgba color)
{
cpVect offset = cam_pos();
offset = cpvmult(offset, 1/cam_zoom());
offset.x -= mainwin->width/2;
offset.y -= mainwin->height/2;
sg_apply_pipeline(grid_pipe);
sg_apply_bindings(&grid_bind);
float col[4] = { color.r/255.0 ,color.g/255.0 ,color.b/255.0 ,color.a/255.0 };
float fubo[6];
fubo[0] = 1;
fubo[1] = span;
memcpy(&fubo[2], col, sizeof(float)*4);
sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(projection));
sg_apply_uniforms(SG_SHADERSTAGE_VS, 1, SG_RANGE_REF(offset));
sg_apply_uniforms(SG_SHADERSTAGE_FS, 0, SG_RANGE_REF(fubo));
sg_draw(0,4,1);
}
void draw_cppoint(struct cpVect point, float r, struct rgba color)
{
struct point_vertex p = {
.pos = point,
.color = color,
.radius = r
};
memcpy(point_b+point_c, &p, sizeof(struct point_vertex));
point_c++;
}
void draw_points(struct cpVect *points, int n, float size, struct rgba color)
{
for (int i = 0; i < n; i++)
draw_cppoint(points[i], size, color);
}
void draw_poly(cpVect *points, int n, struct rgba color)
{
/* Find polygon mesh */
int tric = n - 2;
if (tric < 1) return;
uint32_t tridxs[tric*3];
for (int i = 2, ti = 0; i < n; i++, ti+=3) {
tridxs[ti] = 0;
tridxs[ti+1] = i-1;
tridxs[ti+2] = i;
}
for (int i = 0; i < tric*3; i++)
tridxs[i] += poly_v+poly_sv;
sg_range trip = {
.ptr = tridxs,
.size = sizeof(uint32_t)*3*tric
};
struct poly_vertex polyverts[n];
for (int i = 0; i < n; i++) {
polyverts[i].pos = points[i];
polyverts[i].uv[0] = 0.0;
polyverts[i].uv[1] = 0.0;
polyverts[i].color = color;
}
sg_range ppp = {
.ptr = polyverts,
.size = sizeof(struct poly_vertex)*n
};
memcpy(poly_b+poly_v, polyverts, sizeof(struct poly_vertex)*n);
memcpy(poly_bi+poly_c, tridxs, sizeof(uint32_t)*3*tric);
poly_c += tric*3;
poly_v += n;
}

View File

@@ -0,0 +1,29 @@
#ifndef DEBUGDRAW_H
#define DEBUGDRAW_H
#include <chipmunk/chipmunk.h>
#include "HandmadeMath.h"
struct rgba;
void debugdraw_init();
void draw_cppoint(struct cpVect point, float r, struct rgba color);
void draw_points(struct cpVect *points, int n, float size, struct rgba color);
void draw_line(cpVect *points, int n, struct rgba color, float seg_len, int closed, float seg_speed);
void draw_arrow(struct cpVect start, struct cpVect end, struct rgba, int capsize);
void draw_edge(struct cpVect *points, int n, struct rgba color, int thickness, int closed, int flags, struct rgba line_color, float line_seg);
/* pixels - how many pixels thick, segsize - dashed line seg len */
void draw_circle(cpVect c, float radius, float pixels, struct rgba color, float seg);
void draw_box(cpVect c, cpVect wh, struct rgba color);
void draw_poly(cpVect *points, int n, struct rgba color);
void draw_grid(int width, int span, struct rgba color);
void debug_flush(HMM_Mat4 *view);
void debug_newframe();
cpVect inflatepoint(cpVect a, cpVect b, cpVect c, float d);
void inflatepoints(cpVect *r, cpVect *p, float d, int n);
#endif

87
source/engine/debug/log.c Normal file
View File

@@ -0,0 +1,87 @@
#include "log.h"
#include "render.h"
#include <time.h>
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include "script.h"
int logLevel = 1;
/* Four levels of log:
0 info
1 warn
2 error
3 critical
*/
char *logstr[] = { "info", "warn", "error", "critical" };
char *catstr[] = {"engine", "script", "render"};
FILE *logfile = NULL;
#define CONSOLE_BUF 1024*1024*5/* 5MB */
char lastlog[ERROR_BUFFER+1] = {'\0'};
char consolelog[CONSOLE_BUF+1] = {'\0'};
void mYughLog(int category, int priority, int line, const char *file, const char *message, ...)
{
#ifdef DBG
if (priority >= logLevel) {
time_t now = time(0);
struct tm *tinfo = localtime(&now);
char timestr[50];
strftime(timestr,50,"%y", tinfo);
double ticks = (double)clock()/CLOCKS_PER_SEC;
va_list args;
va_start(args, message);
char msgbuffer[ERROR_BUFFER] = { '\0' };
vsnprintf(msgbuffer, ERROR_BUFFER, message, args);
va_end(args);
char buffer[ERROR_BUFFER] = { '\0' };
snprintf(buffer, ERROR_BUFFER, "%s:%d: %s, %s: %s\n", file, line, logstr[priority], catstr[category], msgbuffer);
log_print(buffer);
// if (category != LOG_SCRIPT && priority >= 2)
// js_stacktrace();
}
#endif
}
void log_print(const char *str)
{
fprintf(stderr, "%s", str);
fflush(stderr);
strncat(consolelog, str, CONSOLE_BUF);
if (logfile) {
fprintf(logfile, "%s", str);
fflush(logfile);
}
snprintf(lastlog, ERROR_BUFFER, "%s", str);
}
void log_setfile(char *file) {
freopen(file, "w", stderr);
freopen(file, "w", stdout);
}
void log_cat(FILE *f) {
char out[1024];
while (fgets(out, sizeof(out), f)) {
out[strcspn(out, "\n")] = '\0';
YughInfo(out);
}
}

View File

@@ -3,26 +3,41 @@
#include <stdio.h>
#define ERROR_BUFFER 2048
#define ERROR_BUFFER 1024*1024
#define LOG_INFO 0
#define LOG_WARN 1
#define LOG_ERROR 2
#define LOG_CRITICAL 3
#define LOG_ENGINE 0
#define LOG_SCRIPT 1
#define LOG_RENDER 2
#define M_PI 3.14
extern char lastlog[];
extern char consolelog[];
extern int logLevel;
#ifdef DBG
#define YughLog(cat, pri, msg, ...) mYughLog(cat, pri, __LINE__, __FILE__, msg, ##__VA_ARGS__)
#define YughInfo(msg, ...) mYughLog(0, 0, __LINE__, __FILE__, msg, ##__VA_ARGS__);
#define YughWarn(msg, ...) mYughLog(0, 1, __LINE__, __FILE__, msg, ##__VA_ARGS__);
#define YughError(msg, ...) mYughLog(0, 2, __LINE__, __FILE__, msg, ##__VA_ARGS__);
#define YughCritical(msg, ...) mYughLog(0, 3, __LINE__, __FILE__, msg, ##__VA_ARGS__);
#else
#define YughLog(cat, pri, msg, ...)
#define YughInfo(msg, ...)
#define YughWarn(msg, ...)
#define YughError(msg, ...)
#define YughCritical(msg, ...)
#endif
void mYughLog(int category, int priority, int line, const char *file, const char *message, ...);
void FlushGLErrors();
int TestSDLError(int sdlErr);
void log_setfile(char *file);
void log_cat(FILE *f);
void log_print(const char *str);
#endif

View File

@@ -1,154 +0,0 @@
#include "debugdraw.h"
#include "openglrender.h"
#include "shader.h"
static uint32_t circleVBO;
static uint32_t circleVAO;
static struct shader *circleShader;
static uint32_t gridVBO;
static uint32_t gridVAO;
static struct shader *gridShader;
static uint32_t rectVBO;
static uint32_t rectVAO;
static struct shader *rectShader;
void debugdraw_init()
{
circleShader = MakeShader("circlevert.glsl", "circlefrag.glsl");
shader_setUBO(circleShader, "Projection", 0);
glGenBuffers(1, &circleVBO);
glGenVertexArrays(1, &circleVAO);
float gridverts[] = {
-1.f, -1.f,
1.f, -1.f,
-1.f, 1.f,
1.f, 1.f
};
gridShader = MakeShader("gridvert.glsl", "gridfrag.glsl");
shader_setUBO(gridShader, "Projection", 0);
glGenBuffers(1, &gridVBO);
glGenVertexArrays(1, &gridVAO);
glBindVertexArray(gridVAO);
glBindBuffer(GL_ARRAY_BUFFER, gridVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(gridverts), &gridverts,
GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL);
rectShader = MakeShader("linevert.glsl", "linefrag.glsl");
shader_setUBO(rectShader, "Projection", 0);
glGenBuffers(1, &rectVBO);
glGenVertexArrays(1, &rectVAO);
}
void draw_line(int x1, int y1, int x2, int y2)
{
shader_use(rectShader);
float verts[] = {
x1, y1,
x2, y2
};
glBindBuffer(GL_ARRAY_BUFFER, rectVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(verts), &verts, GL_DYNAMIC_DRAW);
glBindVertexArray(rectVAO);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glDrawArrays(GL_LINE_STRIP, 0, 2);
}
void draw_edge(float *points, int n)
{
shader_use(rectShader);
glBindBuffer(GL_ARRAY_BUFFER, rectVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * n * 2, points,
GL_DYNAMIC_DRAW);
glBindVertexArray(rectVAO);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glDrawArrays(GL_LINE_STRIP, 0, n);
}
void draw_circle(int x, int y, float radius, int pixels)
{
shader_use(circleShader);
float verts[] = {
x - radius, y - radius, -1.f, -1.f,
x + radius, y - radius, 1.f, -1.f,
x - radius, y + radius, -1.f, 1.f,
x + radius, y + radius, 1.f, 1.f
};
glBindBuffer(GL_ARRAY_BUFFER, circleVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(verts), &verts, GL_DYNAMIC_DRAW);
shader_setfloat(circleShader, "radius", radius);
shader_setint(circleShader, "thickness", pixels);
glBindVertexArray(circleVAO);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, NULL);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
void draw_rect(int x, int y, int w, int h)
{
float hw = w / 2.f;
float hh = h / 2.f;
float verts[] = {
x - hw, y - hh,
x + hw, y - hh,
x + hw, y + hh,
x - hw, y + hh
};
shader_use(rectShader);
glBindBuffer(GL_ARRAY_BUFFER, rectVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(verts), &verts, GL_DYNAMIC_DRAW);
glBindVertexArray(rectVAO);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glDrawArrays(GL_LINE_LOOP, 0, 4);
}
void draw_grid(int width, int span)
{
shader_use(gridShader);
shader_setint(gridShader, "thickness", width);
shader_setint(gridShader, "span", span);
glBindVertexArray(gridVAO);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
void draw_point(int x, int y, float r)
{
draw_circle(x, y, r, r);
}
void draw_poly(float *points, int n)
{
shader_use(rectShader);
glBindBuffer(GL_ARRAY_BUFFER, rectVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * n * 2, points,
GL_DYNAMIC_DRAW);
glBindVertexArray(rectVAO);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glDrawArrays(GL_LINE_LOOP, 0, n);
}
void debugdraw_flush()
{
}

View File

@@ -1,16 +0,0 @@
#ifndef DEBUGDRAW_H
#define DEBUGDRAW_H
void debugdraw_init();
void draw_line(int x1, int y1, int x2, int y2);
void draw_edge(float *points, int n);
void draw_circle(int x, int y, float radius, int pixels);
void draw_grid(int width, int span);
void draw_rect(int x, int y, int w, int h);
void draw_point(int x, int y, float r);
void draw_poly(float *points, int n);
void debugdraw_flush(); /* This is called once per frame to draw all queued elements */
#endif

View File

@@ -1,95 +0,0 @@
#include "ed_project.h"
#include "editor.h"
void editor_init_project(struct gameproject *gp)
{
/*
cur_project = gp;
DATA_PATH = strdup(gp->path);
stemlen = strlen(DATA_PATH);
findPrefabs();
get_levels();
get_all_files();
*/
}
void editor_make_project(char *path)
{
FILE *f = path_open("w", "%s%s", path, "/project.yugh");
cur_project =
(struct gameproject *) malloc(sizeof(struct gameproject));
strncpy(cur_project->name, "New Game", 127);
strncpy(cur_project->path, path, 2048);
vec_add(projects, cur_project);
fwrite(cur_project, sizeof(*cur_project), 1, f);
fclose(f);
editor_init_project(cur_project);
editor_save_projects();
}
void editor_import_project(char *path)
{
FILE *f = path_open("r", "%s%s", path, "/project.yugh");
if (!f)
return;
struct gameproject *gp = (struct gameproject *) malloc(sizeof(*gp));
fread(gp, sizeof(*gp), 1, f);
fclose(f);
vec_add(projects, gp);
}
void editor_project_btn_gui(struct gameproject *gp)
{
/*
if (ImGui::Button(gp->name))
editor_init_project(gp);
ImGui::SameLine();
ImGui::Text("%s", gp->path);
*/
}
void editor_proj_select_gui()
{
/*
ImGui::Begin("Project Select");
vec_walk(projects, (void (*)(void *)) &editor_project_btn_gui);
ImGui::InputText("Project import path", setpath, MAXPATH);
ImGui::SameLine();
if (ImGui::Button("Create")) {
editor_make_project(setpath);
}
ImGui::SameLine();
if (ImGui::Button("Import")) {
editor_import_project(setpath);
}
ImGui::End();
*/
}
void editor_load_projects()
{
FILE *f = fopen("projects.yugh", "r");
if (!f)
return;
vec_load(projects, f);
fclose(f);
}
void editor_save_projects()
{
FILE *f = fopen("projects.yugh", "w");
vec_store(projects, f);
fclose(f);
}

View File

@@ -1,18 +0,0 @@
#ifndef ED_PROJECT_H
#define ED_PROJECT_H
#include "config.h"
struct gameproject {
char name[127];
char path[MAXPATH];
};
void editor_init_project(struct gameproject *gp);
void editor_save_projects();
void editor_load_projects();
void editor_proj_select_gui();
void editor_import_project(char *path);
void editor_make_project(char *path);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,109 +0,0 @@
#ifndef EDITOR_H
#define EDITOR_H
#include <config.h>
#include <stdbool.h>
#include "resources.h"
#include "nuke.h"
#define ASSET_TYPE_NULL 0
#define ASSET_TYPE_IMAGE 1
#define ASSET_TYPE_TEXT 2
#define ASSET_TYPE_SOUND 3
struct fileasset {
char *filename;
bool searched;
short type;
void *data; // Struct of the underlying asset - Texture struct, etc
};
typedef struct {
bool show;
struct nk_rect rect;
} editor_win;
struct editorVars {
editor_win stats;
editor_win hierarchy;
editor_win lighting;
editor_win gamesettings;
editor_win viewmode;
editor_win debug;
editor_win assets;
editor_win asset;
editor_win repl;
editor_win export;
editor_win level;
editor_win gameobject;
editor_win components;
editor_win simulate;
editor_win prefab;
nk_flags text_ed;
nk_flags asset_srch;
};
struct gameobject;
extern int show_desktop;
#define NK_MENU_START(VAR) if (editor.VAR.show && !show_desktop) { \
if (editor.VAR.rect.w == 0) editor.VAR.rect = nk_rect_std; \
if (nk_begin(ctx, #VAR, editor.VAR.rect, nuk_std)) { \
editor.VAR.rect = nk_window_get_bounds(ctx);
#define NK_MENU_END() } nk_end(ctx); }
#define NK_FORCE(VAR) if (editor.VAR.rect.w == 0) editor.VAR.rect = nk_rect_std; \
if (!show_desktop && nk_begin(ctx, #VAR, editor.VAR.rect, nuk_std)) { \
editor.VAR.rect = nk_window_get_bounds(ctx);
#define NK_FORCE_END() nk_end(ctx); }
#define NEGATE(VAR) VAR = ! VAR
struct vec;
struct gameproject;
struct sprite;
extern struct gameproject *cur_project;
extern struct vec *projects;
struct Texture;
struct window;
void pickGameObject(int pickID);
int is_allowed_extension(const char *ext);
void editor_init(struct window *window);
void editor_input();
void editor_render();
int editor_wantkeyboard();
void editor_save();
void editor_makenewobject();
void editor_project_gui();
void editor_selectasset(struct fileasset *asset);
void editor_selectasset_str(const char *path);
void editor_asset_gui(struct fileasset *asset);
void editor_asset_tex_gui(struct Texture *tex);
void editor_asset_text_gui(char *text);
void editor_level_btn(char *level);
void editor_prefab_btn(char *prefab);
void game_start();
void game_resume();
void game_stop();
void game_pause();
void get_levels();
int obj_gui_hierarchy(struct gameobject *selected);
void sprite_gui(struct sprite *sprite);
#endif

View File

@@ -1,19 +0,0 @@
#include "editorstate.h"
#include <stdio.h>
/*
void (*asset_command)(char *asset) = print_file;
void print_file(char *file)
{
YughInfo("File path: %s", file);
}
void set_new_model(char *modelPath)
{
printf("Loading new model: %s\n", modelPath);
curActor->model = GetExistingModel(modelPath);
strcpy(curActor->currentModelPath, modelPath);
}
*/

View File

@@ -1,10 +0,0 @@
#ifndef EDITORSTATE_H
#define EDITORSTATE_H
void set_new_model(char *modelPath);
extern void (*asset_command)(char *asset);
void print_file(char *file);
#endif

View File

@@ -10,65 +10,52 @@
#define STBI_FAILURE_USERMSG
#include "stb_image.h"
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"
#define PL_MPEG_IMPLEMENTATION
#include <pl_mpeg.h>
#ifdef EDITOR
#include "editor.h"
#endif
#include "render.h"
#include "openglrender.h"
#include "window.h"
#include "camera.h"
#include "input.h"
#include "sprite.h"
#include "2dphysics.h"
#include "camera.h"
#include "gameobject.h"
#include "registry.h"
#include "input.h"
#include "log.h"
#include "openglrender.h"
#include "resources.h"
#include "timer.h"
#include "script.h"
#include "sprite.h"
#include "timer.h"
#include "window.h"
#include "sound.h"
// TODO: Init on the heap
#include "engine.h"
void error_callback(int error, const char *description)
{
fprintf(stderr, "Error: %s\n", description);
YughError("GLFW Error: %s", description);
void error_callback(int error, const char *description) {
fprintf(stderr, "Error: %s\n", description);
YughError("GLFW Error: %s", description);
}
void engine_init()
{
glfwSetErrorCallback(error_callback);
/* Initialize GLFW */
if (!glfwInit()) {
YughError("Could not init GLFW. Exiting.");
exit(1);
}
void engine_init() {
glfwSetErrorCallback(error_callback);
/* Initialize GLFW */
if (!glfwInit()) {
YughError("Could not init GLFW. Exiting.");
exit(1);
} else {
YughInfo("Initted GLFW.");
}
resources_init();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
YughInfo("Starting physics ...");
phys2d_init();
YughInfo("Starting sound ...");
sound_init();
resources_init();
script_init();
registry_init();
//stbi_set_flip_vertically_on_load(1);
phys2d_init();
sound_init();
}
void engine_stop()
{
glfwTerminate();
YughInfo("Starting scripts ...");
script_init();
}

View File

@@ -1,23 +1,10 @@
#ifndef ENGINE_H
#define ENGINE_H
#define FPS30 33
#define FPS60 17
#define FPS120 8
#define FPS144 7
#define FPS300 3
#define sFPS30 0.033
#define sFPS60 0.017
#define sFPS120 0.008
#define sFPS144 0.007
#define sFPS300 0.003
extern double renderMS;
extern double physMS;
extern double updateMS;
void engine_init();
void engine_stop();
#endif

1640
source/engine/ffi.c Normal file

File diff suppressed because it is too large Load Diff

22
source/engine/ffi.h Normal file
View File

@@ -0,0 +1,22 @@
#ifndef FFI_H
#define FFI_H
#include "quickjs/quickjs.h"
#include <chipmunk/chipmunk.h>
#include "2dphysics.h"
void ffi_load();
JSValue vec2js(cpVect v);
cpVect js2vec2(JSValue v);
JSValue bitmask2js(cpBitmask mask);
cpBitmask js2bitmask(JSValue v);
struct rgba js2color(JSValue v);
double js2number(JSValue v);
JSValue num2js(double g);
JSValue int2js(int i);
JSValue str2js(const char *c);
#endif

View File

@@ -1,240 +1,412 @@
#include "font.h"
#include "log.h"
#include "render.h"
#include <shader.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <shader.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <window.h>
#include "log.h"
#include <chipmunk/chipmunk.h>
#include "2dphysics.h"
#include <stb_truetype.h>
#include "openglrender.h"
static uint32_t VBO = 0;
static uint32_t VAO = 0;
#include "stb_image_write.h"
#include "stb_rect_pack.h"
#include "stb_truetype.h"
unsigned char ttf_buffer[1<<25];
unsigned char temp_bitmap[512 * 512];
#include "HandmadeMath.h"
struct sFont *font;
static struct shader *shader;
#define max_chars 40000
unsigned char *slurp_file(const char *filename) {
FILE *f = fopen(filename, "rb");
if (!f) return NULL;
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
fseek(f, 0, SEEK_SET);
unsigned char *slurp = malloc(fsize + 1);
fread(slurp, fsize, 1, f);
fclose(f);
return slurp;
}
char *slurp_text(const char *filename) {
FILE *f = fopen(filename, "r'");
if (!f) {
YughWarn("File %s doesn't exist.", filename);
return NULL;
}
char *buf;
long int fsize;
fseek(f, 0, SEEK_END);
fsize = ftell(f);
buf = malloc(fsize + 1);
rewind(f);
size_t r = fread(buf, sizeof(char), fsize, f);
buf[r] = '\0';
fclose(f);
return buf;
}
int slurp_write(const char *txt, const char *filename) {
FILE *f = fopen(filename, "w");
if (!f) return 1;
fputs(txt, f);
fclose(f);
return 0;
}
static sg_shader fontshader;
static sg_bindings bind_text;
static sg_pipeline pipe_text;
struct text_vert {
cpVect pos;
cpVect wh;
struct uv_n uv;
struct uv_n st;
struct rgba color;
};
static struct text_vert text_buffer[max_chars];
void font_init(struct shader *textshader) {
shader = textshader;
fontshader = sg_compile_shader("shaders/textvert.glsl", "shaders/textfrag.glsl", &(sg_shader_desc){
.vs.uniform_blocks[0] = {
.size = sizeof(float) * 16,
// .layout = SG_UNIFORMLAYOUT_STD140,
.uniforms = {
[0] = {.name = "projection", .type = SG_UNIFORMTYPE_MAT4}}},
shader_use(shader);
.fs.images[0] = {.name = "text", .image_type = SG_IMAGETYPE_2D, .sampler_type = SG_SAMPLERTYPE_FLOAT}});
// configure VAO/VBO for texture quads
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
pipe_text = sg_make_pipeline(&(sg_pipeline_desc){
.shader = fontshader,
.layout = {
.attrs = {
[0].format = SG_VERTEXFORMAT_FLOAT2, /* verts */
[0].buffer_index = 1,
[1].format = SG_VERTEXFORMAT_FLOAT2, /* pos */
[2].format = SG_VERTEXFORMAT_FLOAT2, /* width and height */
[3].format = SG_VERTEXFORMAT_USHORT2N, /* uv pos */
[4].format = SG_VERTEXFORMAT_USHORT2N, /* uv width and height */
[5].format = SG_VERTEXFORMAT_UBYTE4N, /* color */
},
.buffers[0].step_func = SG_VERTEXSTEP_PER_INSTANCE
},
.primitive_type = SG_PRIMITIVETYPE_TRIANGLE_STRIP,
.colors[0].blend = blend_trans,
});
float text_verts[8] = {
0,0,
0,1,
1,0,
1,1
};
bind_text.vertex_buffers[1] = sg_make_buffer(&(sg_buffer_desc){
.data = SG_RANGE(text_verts),
.usage = SG_USAGE_IMMUTABLE
});
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 4 * 4, NULL, GL_DYNAMIC_DRAW);
bind_text.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
.size = sizeof(struct text_vert)*max_chars,
.type = SG_BUFFERTYPE_VERTEXBUFFER,
.usage = SG_USAGE_STREAM,
.label = "text buffer"});
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
// Default font
font = MakeFont("teenytinypixels.ttf", 300);
font = MakeFont("LessPerfectDOSVGA.ttf", 16);
bind_text.fs_images[0] = font->texID;
}
void font_frame(struct window *w) {
shader_use(shader);
}
// Height in pixels
struct sFont *MakeFont(const char *fontfile, int height)
struct sFont *MakeSDFFont(const char *fontfile, int height)
{
shader_use(shader);
YughInfo("Making sdf font %s.", fontfile);
struct sFont *newfont = calloc(1, sizeof(struct sFont));
newfont->height = height;
int packsize = 1024;
struct sFont *newfont = calloc(1, sizeof(struct sFont));
newfont->height = height;
char fontpath[256];
snprintf(fontpath, 256, "fonts/%s", fontfile);
fread(ttf_buffer, 1, 1<<25, fopen(fontpath, "rb"));
char fontpath[256];
snprintf(fontpath, 256, "fonts/%s", fontfile);
unsigned char *ttf_buffer = slurp_file(fontpath);
unsigned char *bitmap = malloc(packsize * packsize);
stbtt_fontinfo fontinfo;
if (!stbtt_InitFont(&fontinfo, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer,0))) {
YughError("Failed to make font %s", fontfile);
}
stbtt_fontinfo fontinfo;
if (!stbtt_InitFont(&fontinfo, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer, 0))) {
YughError("Failed to make font %s", fontfile);
}
float scale = stbtt_ScaleForPixelHeight(&fontinfo, height);
int ascent, descent, linegap;
stbtt_GetFontVMetrics(&fontinfo, &ascent, &descent, &linegap);
ascent = roundf(ascent*scale);
descent = roundf(descent*scale);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
for (unsigned char c = 32; c < 128; c++) {
unsigned char *bitmap;
int advance, lsb, w, h, x0, y0;
stbtt_GetCodepointHMetrics(&fontinfo, c, &advance, &lsb);
bitmap = stbtt_GetCodepointBitmap(&fontinfo, scale, scale, c, &w, &h, &x0, &y0);
GLuint ftexture;
glGenTextures(1, &ftexture);
glBindTexture(GL_TEXTURE_2D, ftexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, w, h, 0, GL_RED, GL_UNSIGNED_BYTE, bitmap);
glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);
newfont->Characters[c].TextureID = ftexture;
newfont->Characters[c].Advance = advance * scale;
newfont->Characters[c].Size[0] = w;
newfont->Characters[c].Size[1] = h;
newfont->Characters[c].Bearing[0] = x0;
newfont->Characters[c].Bearing[1] = y0*-1;
}
return newfont;
for (int i = 32; i < 95; i++) {
int w, h, xoff, yoff;
// unsigned char *stbtt_GetGlyphSDF(&fontinfo, height, i, 1, 0, 1, &w, &h, &xoff, &yoff);
}
}
void sdrawCharacter(struct Character c, mfloat_t cursor[2], float scale, struct shader *shader, float color[3])
{
float w = c.Size[0] * scale;
float h = c.Size[1] * scale;
struct sFont *MakeFont(const char *fontfile, int height) {
YughInfo("Making font %s.", fontfile);
float xpos = cursor[0] + c.Bearing[0] * scale;
float ypos = cursor[1] + (c.Bearing[1] * scale) - h;
int packsize = 1024;
float verts[4 * 4] = {
xpos, ypos, 0.f, 0.f,
xpos+w, ypos, 1.f, 0.f,
xpos, ypos + h, 0.f, 1.f,
xpos + w, ypos + h, 1.f, 1.f
};
struct sFont *newfont = calloc(1, sizeof(struct sFont));
newfont->height = height;
char fontpath[256];
snprintf(fontpath, 256, "fonts/%s", fontfile);
////// Outline calculation
// float outlineWidth = 1.1;
unsigned char *ttf_buffer = slurp_file(fontpath);
unsigned char *bitmap = malloc(packsize * packsize);
// float ow = c.Size[0] * scale * outlineWidth;
// float oh = c.Size[1] * scale * outlineWidth;
stbtt_packedchar glyphs[95];
// float oxpos = cursor[0] + c.Bearing[0] * scale * outlineWidth - ((ow-w)/2);
// float oypos = cursor[1] - (c.Size[1] - c.Bearing[1]) * scale * outlineWidth - ((oh-h)/2);
stbtt_pack_context pc;
// float overts[4*4] = {
// oxpos, oypos + oh, 0.f, 0.f,
// oxpos, oypos, 0.f, 1.f,
// oxpos + ow, oypos + oh, 1.f, 0.f,
// oxpos + ow, oypos, 1.f, 1.f
// };
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);
/////////// Shadow calculation
stbi_write_png("packedfont.png", packsize, packsize, 1, bitmap, sizeof(char) * packsize);
stbtt_fontinfo fontinfo;
if (!stbtt_InitFont(&fontinfo, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer, 0))) {
YughError("Failed to make font %s", fontfile);
}
float shadowOffset = 6.f;
float sxpos = cursor[0] + c.Bearing[0] * scale + (scale * shadowOffset);
float sypos = cursor[1] - (c.Size[1] - c.Bearing[1]) * scale - (scale * shadowOffset);
stbtt_GetFontVMetrics(&fontinfo, &newfont->ascent, &newfont->descent, &newfont->linegap);
newfont->emscale = stbtt_ScaleForMappingEmToPixels(&fontinfo, 16);
newfont->linegap = (newfont->ascent - newfont->descent)* 2 * newfont->emscale;
float sverts[4 * 4] = {
sxpos, sypos, 0.f, 0.f,
sxpos+w, sypos, 1.f, 0.f,
sxpos, sypos + h, 0.f, 1.f,
sxpos + w, sypos+h, 1.f, 1.f
};
newfont->texID = sg_make_image(&(sg_image_desc){
.type = SG_IMAGETYPE_2D,
.width = packsize,
.height = packsize,
.pixel_format = SG_PIXELFORMAT_R8,
.usage = SG_USAGE_IMMUTABLE,
.min_filter = SG_FILTER_NEAREST,
.mag_filter = SG_FILTER_NEAREST,
.data.subimage[0][0] = {
.ptr = bitmap,
.size = packsize * packsize}});
free(ttf_buffer);
free(bitmap);
glBindTexture(GL_TEXTURE_2D, c.TextureID);
for (unsigned char c = 32; c < 127; c++) {
stbtt_packedchar glyph = glyphs[c - 32];
//// Shadow pass
struct glrect r;
r.s0 = (glyph.x0) / (float)packsize;
r.s1 = (glyph.x1) / (float)packsize;
r.t0 = (glyph.y0) / (float)packsize;
r.t1 = (glyph.y1) / (float)packsize;
float black[3] = { 0, 0, 0 };
shader_setvec3(shader, "textColor", black);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(sverts), sverts);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
stbtt_GetCodepointHMetrics(&fontinfo, c, &newfont->Characters[c].Advance, &newfont->Characters[c].leftbearing);
newfont->Characters[c].Advance *= newfont->emscale;
newfont->Characters[c].leftbearing *= newfont->emscale;
// newfont->Characters[c].Advance = glyph.xadvance; /* x distance from this char to the next */
newfont->Characters[c].Size[0] = glyph.x1 - glyph.x0;
newfont->Characters[c].Size[1] = glyph.y1 - glyph.y0;
newfont->Characters[c].Bearing[0] = glyph.xoff;
newfont->Characters[c].Bearing[1] = glyph.yoff2;
newfont->Characters[c].rect = r;
}
//// Character pass
shader_setvec3(shader, "textColor", color);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(verts), verts);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
return newfont;
}
void text_settype(struct sFont *mfont)
static int curchar = 0;
void draw_char_box(struct Character c, cpVect cursor, float scale, struct rgba color)
{
font = mfont;
cpVect wh;
wh.x = 8 * scale;
wh.y = 14;
cursor.x += wh.x / 2.f;
cursor.y += wh.y / 2.f;
// draw_box(cursor, wh, color);
}
void renderText(const char *text, mfloat_t pos[2], float scale, mfloat_t color[3], float lw)
{
//shader_use(shader);
shader_setvec3(shader, "textColor", color);
void text_flush(HMM_Mat4 *proj) {
if (curchar == 0) return;
sg_apply_pipeline(pipe_text);
sg_apply_bindings(&bind_text);
sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(*proj));
mfloat_t cursor[2] = { 0.f };
cursor[0] = pos[0];
cursor[1] = pos[1];
sg_range verts;
verts.ptr = text_buffer;
verts.size = sizeof(struct text_vert) * curchar;
sg_update_buffer(bind_text.vertex_buffers[0], &verts);
glActiveTexture(GL_TEXTURE0);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
sg_draw(0, 4, curchar);
curchar = 0;
}
const unsigned char *line, *wordstart;
line = (unsigned char*)text;
static int drawcaret = 0;
void sdrawCharacter(struct Character c, HMM_Vec2 cursor, float scale, struct rgba color) {
struct text_vert vert;
while (*line != '\0') {
float lsize = 1.0 / 1024.0;
switch (*line) {
case '\n':
cursor[1] -= scale * font->height;
line++;
break;
float oline = 0.0;
vert.pos.x = cursor.X + c.Bearing[0] * scale + oline;
vert.pos.y = cursor.Y - c.Bearing[1] * scale - oline;
vert.wh.x = c.Size[0] * scale + (oline*2);
vert.wh.y = c.Size[1] * scale + (oline*2);
vert.uv.u = (c.rect.s0 - oline*lsize)*USHRT_MAX;
vert.uv.v = (c.rect.t0 - oline*lsize)*USHRT_MAX;
vert.st.u = (c.rect.s1-c.rect.s0+oline*lsize*2.0)*USHRT_MAX;
vert.st.v = (c.rect.t1-c.rect.t0+oline*lsize*2.0)*USHRT_MAX;
vert.color = color;
case ' ':
sdrawCharacter(font->Characters[*line], cursor, scale, shader, color);
cursor[0] += font->Characters[*line].Advance * scale;
line++;
break;
memcpy(text_buffer + curchar, &vert, sizeof(struct text_vert));
curchar++;
return;
default:
wordstart = line;
int wordWidth = 0;
while (!isspace(*line) && *line != '\0') {
wordWidth += font->Characters[*line].Advance * scale;
line++;
}
if (lw > 0 && (cursor[0] + wordWidth - pos[0]) >= lw) {
cursor[0] = pos[0];
cursor[1] -= scale * font->height;
}
while (wordstart < line) {
sdrawCharacter(font->Characters[*wordstart], cursor, scale, shader, color);
cursor[0] += font->Characters[*wordstart].Advance * scale;
wordstart++;
}
/*
if (drawcaret == curchar) {
draw_char_box(c, cursor, scale, color);
shader_use(shader);
}
}
*/
/*
sg_append_buffer(bind_text.vertex_buffers[0], SG_RANGE_REF(verts));
offset[0] = 1;
offset[1] = -1;
fill_charverts(verts, cursor, scale, c, offset);
sg_update_buffer(bind_text.vertex_buffers[0], SG_RANGE_REF(verts));
/*
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
*/
offset[1] = 1;
fill_charverts(verts, cursor, scale, c, offset);
sg_update_buffer(bind_text.vertex_buffers[0], SG_RANGE_REF(verts));
offset[0] = -1;
offset[1] = -1;
fill_charverts(verts, cursor, scale, c, offset);
sg_update_buffer(bind_text.vertex_buffers[0], SG_RANGE_REF(verts));
*/
}
void text_settype(struct sFont *mfont) {
font = mfont;
}
struct boundingbox text_bb(const char *text, float scale, float lw, float tracking)
{
HMM_Vec2 cursor = {0,0};
unsigned char *c = text;
unsigned char *wordstart;
while (*c != '\0') {
if (isblank(*c)) {
cursor.X += font->Characters[*c].Advance * tracking * scale;
c++;
} else if (isspace(*c)) {
cursor.Y -= scale * font->linegap;
cursor.X = 0;
c++;
} else {
wordstart = c;
int wordwidth = 0;
while (!isspace(*c) && *c != '\0') {
wordwidth += font->Characters[*c].Advance * tracking * scale;
c++;
}
if (lw > 0 && (cursor.X + wordwidth) >= lw) {
cursor.X = 0;
cursor.Y -= scale * font->linegap;
}
while (wordstart < c) {
cursor.X += font->Characters[*wordstart].Advance * tracking * scale;
wordstart++;
}
}
}
float height = cursor.Y + (font->height*scale);
float width = lw > 0 ? lw : cursor.X;
struct boundingbox bb = {};
bb.l = 0;
bb.t = font->ascent * font->emscale * scale;
bb.b = font->descent * font->emscale * scale;
bb.r = cursor.X;
return bb;
return cwh2bb((HMM_Vec2){0,0}, (HMM_Vec2){width,height});
}
int renderText(const char *text, HMM_Vec2 pos, float scale, struct rgba color, float lw, int caret, float tracking) {
int len = strlen(text);
drawcaret = caret;
HMM_Vec2 cursor = pos;
const unsigned char *line, *wordstart, *drawstart;
line = drawstart = (unsigned char *)text;
struct rgba usecolor = color;
while (*line != '\0') {
if (isblank(*line)) {
sdrawCharacter(font->Characters[*line], cursor, scale, usecolor);
cursor.X += font->Characters[*line].Advance * tracking * scale;
line++;
} else if (isspace(*line)) {
sdrawCharacter(font->Characters[*line], cursor, scale, usecolor);
cursor.Y -= scale * font->linegap;
cursor.X = pos.X;
line++;
} else {
wordstart = line;
int wordWidth = 0;
while (!isspace(*line) && *line != '\0') {
wordWidth += font->Characters[*line].Advance * tracking * scale;
line++;
}
if (lw > 0 && (cursor.X + wordWidth - pos.X) >= lw) {
cursor.X = pos.X;
cursor.Y -= scale * font->linegap;
}
while (wordstart < line) {
sdrawCharacter(font->Characters[*wordstart], cursor, scale, usecolor);
cursor.X += font->Characters[*wordstart].Advance * tracking * scale;
wordstart++;
}
}
}
/* if (caret > curchar) {
draw_char_box(font->Characters[69], cursor, scale, color);
}
*/
return cursor.Y - pos.Y;
}

View File

@@ -1,33 +1,47 @@
#ifndef FONT_H
#define FONT_H
#include "mathc.h"
#include "sokol/sokol_gfx.h"
#include "texture.h"
#include "2dphysics.h"
#include "HandmadeMath.h"
struct shader;
struct window;
/// Holds all state information relevant to a character as loaded using FreeType
struct Character {
uint32_t TextureID; // ID handle of the glyph texture
mfloat_t Size[2]; // Size of glyph
mfloat_t Bearing[2]; // Offset from baseline to left/top of glyph
unsigned int Advance; // Horizontal offset to advance to next glyph
float Size[2]; // Size of glyph
float Bearing[2]; // Offset from baseline to left/top of glyph
int Advance; // Horizontal offset to advance to next glyph
int leftbearing;
struct glrect rect;
};
struct sFont {
uint32_t fontTexture;
uint32_t height;
struct Character Characters[127];
uint32_t fontTexture;
uint32_t height; /* in pixels */
int ascent;
int descent;
int linegap;
float emscale;
struct Character Characters[127];
sg_image texID;
};
void font_init(struct shader *s);
void font_frame(struct window *w);
struct sFont *MakeFont(const char *fontfile, int height);
void sdrawCharacter(struct Character c, mfloat_t cursor[2], float scale, struct shader *shader, float color[3]);
void sdrawCharacter(struct Character c, HMM_Vec2 cursor, float scale, struct rgba color);
void text_settype(struct sFont *font);
void renderText(const char *text, mfloat_t pos[2], float scale, mfloat_t color[3], float lw);
struct boundingbox text_bb(const char *text, float scale, float lw, float tracking);
int renderText(const char *text, HMM_Vec2 pos, float scale, struct rgba color, float lw, int caret, float tracking);
// void text_frame();
void text_flush(HMM_Mat4 *proj);
unsigned char *slurp_file(const char *filename);
char *slurp_text(const char *filename);
int slurp_write(const char *txt, const char *filename);
#endif

View File

@@ -1,302 +1,370 @@
#include "gameobject.h"
#include "2dphysics.h"
#include "debugdraw.h"
#include "input.h"
#include "log.h"
#include "nuke.h"
#include "resources.h"
#include "script.h"
#include "shader.h"
#include "sprite.h"
#include "registry.h"
#include "2dphysics.h"
#include "script.h"
#include "input.h"
#include <string.h>
#include <chipmunk/chipmunk.h>
#include "resources.h"
#include "nuke.h"
#include "log.h"
#include <string.h>
#include "debugdraw.h"
#include "stb_ds.h"
struct gameobject *gameobjects = NULL;
static int first = -1;
const int nameBuf[MAXNAME] = { 0 };
const int prefabNameBuf[MAXNAME] = { 0 };
const int nameBuf[MAXNAME] = {0};
const int prefabNameBuf[MAXNAME] = {0};
struct gameobject *get_gameobject_from_id(int id)
{
return &gameobjects[id];
struct gameobject *get_gameobject_from_id(int id) {
if (id < 0) return NULL;
return &gameobjects[id];
}
static void gameobject_setpickcolor(struct gameobject *go)
{
float r = ((go->editor.id & 0x000000FF) >> 0) / 255.f;
float g = ((go->editor.id & 0x0000FF00) >> 8) / 255.f;
float b = ((go->editor.id & 0x00FF0000) >> 16) / 255.f;
struct gameobject *id2go(int id) {
if (id < 0) return NULL;
go->editor.color[0] = r;
go->editor.color[1] = g;
go->editor.color[2] = b;
return &gameobjects[id];
}
struct gameobject *MakeGameobject()
{
YughInfo("Making new gameobject");
struct gameobject go = {
.editor.id = arrlen(gameobjects),
.transform.scale = 1.f,
.scale = 1.f,
.bodytype = CP_BODY_TYPE_STATIC,
.mass = 1.f
};
int body2id(cpBody *body) {
return (int)cpBodyGetUserData(body);
}
gameobject_setpickcolor(&go);
strncpy(go.editor.mname, "New object", MAXNAME);
go.body = cpSpaceAddBody(space, cpBodyNew(go.mass, 1.f));
cpBody *id2body(int id) {
struct gameobject *go = id2go(id);
if (go)
return go->body;
return NULL;
}
int shape2gameobject(cpShape *shape) {
struct phys2d_shape *s = cpShapeGetUserData(shape);
return s->go;
}
int pos2gameobject(cpVect pos) {
cpShape *hit = phys2d_query_pos(pos);
if (hit) {
return shape2gameobject(hit);
}
for (int i = 0; i < arrlen(gameobjects); i++) {
if (!gameobjects[i].body) continue;
cpVect gpos = cpBodyGetPosition(gameobjects[i].body);
float dist = cpvlength(cpvsub(gpos, pos));
if (dist <= 25) return i;
}
return -1;
}
int id_from_gameobject(struct gameobject *go) {
for (int i = 0; i < arrlen(gameobjects); i++) {
if (&gameobjects[i] == go) return i;
}
return -1;
}
void gameobject_set_sensor(int id, int sensor) {
id2go(id)->sensor = sensor;
gameobject_apply(id2go(id));
}
int go2id(struct gameobject *go) {
return id_from_gameobject(go);
}
void go_shape_apply(cpBody *body, cpShape *shape, struct gameobject *go) {
cpShapeSetFriction(shape, go->f);
cpShapeSetElasticity(shape, go->e);
cpShapeSetCollisionType(shape, go2id(go));
cpShapeFilter filter;
filter.group = go2id(go);
filter.categories = CP_ALL_CATEGORIES;//1<<go->layer;
filter.mask = CP_ALL_CATEGORIES;//category_masks[go->layer];
cpShapeSetFilter(shape, filter);
}
void go_shape_moi(cpBody *body, cpShape *shape, struct gameobject *go) {
float moment = cpBodyGetMoment(go->body);
struct phys2d_shape *s = cpShapeGetUserData(shape);
if (!s) {
cpBodySetMoment(go->body, moment + 1);
return;
}
moment += s->moi(s->data, go->mass);
if (moment < 0) moment = 1;
cpBodySetMoment(go->body, moment);
}
void gameobject_apply(struct gameobject *go) {
cpBodySetType(go->body, go->bodytype);
cpBodyEachShape(go->body, go_shape_apply, go);
if (go->bodytype == CP_BODY_TYPE_DYNAMIC) {
cpBodySetMass(go->body, go->mass);
cpBodySetMoment(go->body, 0.f);
cpBodyEachShape(go->body, go_shape_moi, go);
if (cpBodyGetMoment(go->body) <= 0.f)
cpBodySetMoment(go->body, 1.f);
return;
}
}
static void gameobject_setpickcolor(struct gameobject *go) {
/*
float r = ((go->editor.id & 0x000000FF) >> 0) / 255.f;
float g = ((go->editor.id & 0x0000FF00) >> 8) / 255.f;
float b = ((go->editor.id & 0x00FF0000) >> 16) / 255.f;
go->editor.color[0] = r;
go->editor.color[1] = g;
go->editor.color[2] = b;
*/
}
int MakeGameobject() {
struct gameobject go = {
.scale = 1.f,
.bodytype = CP_BODY_TYPE_STATIC,
.mass = 1.f,
.next = -1,
.sensor = 0,
.shape_cbs = NULL,
.ref = JS_NULL,
};
go.cbs.begin.obj = JS_NULL;
go.cbs.separate.obj = JS_NULL;
go.body = cpSpaceAddBody(space, cpBodyNew(go.mass, 1.f));
int retid;
if (first < 0) {
arrput(gameobjects, go);
retid = arrlast(gameobjects).id = arrlen(gameobjects) - 1;
} else {
retid = first;
first = id2go(first)->next;
*id2go(retid) = go;
}
return &arrlast(gameobjects);
cpBodySetUserData(go.body, (void *)retid);
phys2d_setup_handlers(retid);
return retid;
}
void gameobject_addcomponent(struct gameobject *go, struct component *c)
{
arrput(go->components, *c);
struct component *newc = &arrlast(go->components);
newc->go = go;
newc->data = newc->make(newc->go);
void rm_body_shapes(cpBody *body, cpShape *shape, void *data) {
struct phys2d_shape *s = cpShapeGetUserData(shape);
if (s->data) {
free(s->data);
s->data = NULL;
}
cpSpaceRemoveShape(space, shape);
cpShapeFree(shape);
}
void gameobject_delete(int id)
{
YughInfo("Deleting gameobject with id %d.", id);
struct gameobject *go = &gameobjects[id];
for (int i = 0; i < arrlen(go->components); i++) {
go->components[i].delete(go->components[i].data);
arrdel(go->components, i);
}
int *go_toclean = NULL;
arrdelswap(gameobjects, id);
/* Free this gameobject */
void gameobject_clean(int id) {
struct gameobject *go = id2go(id);
arrfree(go->shape_cbs);
cpBodyEachShape(go->body, rm_body_shapes, NULL);
cpSpaceRemoveBody(space, go->body);
cpBodyFree(go->body);
go->body = NULL;
}
void gameobject_delcomponent(struct gameobject *go, int n)
{
go->components[n].delete(go->components[n].data);
arrdel(go->components, n);
/* Really more of a "mark for deletion" ... */
void gameobject_delete(int id) {
id2go(id)->next = first;
first = id;
if (cpSpaceIsLocked(space))
arrpush(go_toclean, id);
else
gameobject_clean(id);
}
void setup_model_transform(struct mTransform *t, struct shader *s, float scale)
{
mfloat_t modelT[16] = { 0.f };
mfloat_t matbuff[16] = { 0.f };
memcpy(modelT, UNITMAT4, sizeof(modelT));
mat4_translate_vec3(modelT, t->position);
mat4_multiply(modelT, modelT, mat4_rotation_quat(matbuff, t->rotation));
mat4_scale_vec3f(modelT, scale);
shader_setmat4(s, "model", modelT);
void gameobjects_cleanup() {
for (int i = 0; i < arrlen(go_toclean); i++)
gameobject_clean(go_toclean[i]);
arrsetlen(go_toclean, 0);
return;
int clean = first;
while (clean >= 0 && id2go(clean)->body) {
gameobject_clean(clean);
clean = id2go(clean)->next;
}
}
void gameobject_save(struct gameobject *go, FILE * file)
{
fwrite(go, sizeof(*go), 1, file);
void gameobject_move(struct gameobject *go, cpVect vec) {
cpVect p = cpBodyGetPosition(go->body);
p.x += vec.x;
p.y += vec.y;
cpBodySetPosition(go->body, p);
YughInfo("Number of components is %d.", arrlen(go->components));
int n = arrlen(go->components);
fwrite(&n, sizeof(n), 1, file);
for (int i = 0; i < n; i++) {
fwrite(&go->components[i].id, sizeof(int), 1, file);
if (go->components[i].io == NULL)
fwrite(go->components[i].data, go->components[i].datasize, 1, file);
else
go->components[i].io(go->components[i].data, file, 0);
}
phys2d_reindex_body(go->body);
}
void gameobject_makefromprefab(char *path)
{
FILE *fprefab = fopen(path, "rb");
if (fprefab == NULL) {
return;
}
void gameobject_rotate(struct gameobject *go, float as) {
cpFloat a = cpBodyGetAngle(go->body);
a += as * deltaT;
cpBodySetAngle(go->body, a);
struct gameobject *new = MakeGameobject();
fread(new, sizeof(*new), 1, fprefab);
new->components = NULL;
gameobject_init(new, fprefab);
fclose(fprefab);
phys2d_reindex_body(go->body);
}
void gameobject_init(struct gameobject *go, FILE * fprefab)
{
go->body = cpSpaceAddBody(space, cpBodyNew(go->mass, 1.f));
int comp_n;
fread(&comp_n, sizeof(int), 1, fprefab);
arrfree(go->components);
int n;
for (int i = 0; i < comp_n; i++) {
/*
fread(&n, sizeof(int), 1, fprefab);
go->components[i] = components[n];
struct component *newc = &go->components[i];
newc->go = go;
newc->data = calloc(1, newc->datasize);
*/
fread(&n, sizeof(int), 1, fprefab);
arrput(go->components, components[n]);
struct component *newc = &arrlast(go->components);
newc->go = go;
newc->data = newc->make(newc->go);
if (newc->io == NULL)
fread(newc->data, newc->datasize, 1, fprefab);
else
newc->io(newc->data, fprefab, 1);
newc->init(newc->data, go);
}
void gameobject_setangle(struct gameobject *go, float angle) {
cpBodySetAngle(go->body, angle);
phys2d_reindex_body(go->body);
}
void gameobject_saveprefab(struct gameobject *go)
{
char prefabfname[60] = { '\0' };
strncat(prefabfname, go->editor.prefabName, MAXNAME);
strncat(prefabfname, EXT_PREFAB, 10);
FILE *pfile = fopen(prefabfname, "wb+");
gameobject_save(go, pfile);
fclose(pfile);
void gameobject_setpos(struct gameobject *go, cpVect vec) {
if (!go || !go->body) return;
cpBodySetPosition(go->body, vec);
findPrefabs();
phys2d_reindex_body(go->body);
}
void object_gui(struct gameobject *go) {
/*
float temp_pos[2];
draw_cppoint(cpBodyGetPosition(go->body), 3);
nuke_property_float2("Position", -1000000.f, temp_pos, 1000000.f, 1.f, 0.5f);
cpVect tvect = { temp_pos[0], temp_pos[1] };
cpBodySetPosition(go->body, tvect);
float mtry = cpBodyGetAngle(go->body);
float modtry = fmodf(mtry * RAD2DEGS, 360.f);
if (modtry < 0.f)
modtry += 360.f;
float modtry2 = modtry;
nuke_property_float("Angle", -1000.f, &modtry, 1000.f, 0.5f, 0.5f);
modtry -= modtry2;
cpBodySetAngle(go->body, mtry + (modtry * DEG2RADS));
nuke_property_float("Scale", 0.f, &go->scale, 1000.f, 0.01f, go->scale * 0.01f);
nuke_nel(3);
nuke_radio_btn("Static", &go->bodytype, CP_BODY_TYPE_STATIC);
nuke_radio_btn("Dynamic", &go->bodytype, CP_BODY_TYPE_DYNAMIC);
nuke_radio_btn("Kinematic", &go->bodytype, CP_BODY_TYPE_KINEMATIC);
cpBodySetType(go->body, go->bodytype);
if (go->bodytype == CP_BODY_TYPE_DYNAMIC) {
nuke_property_float("Mass", 0.01f, &go->mass, 1000.f, 0.01f, 0.01f);
cpBodySetMass(go->body, go->mass);
}
nuke_property_float("Friction", 0.f, &go->f, 10.f, 0.01f, 0.01f);
nuke_property_float("Elasticity", 0.f, &go->e, 2.f, 0.01f, 0.01f);
int n = -1;
for (int i = 0; i < arrlen(go->components); i++) {
struct component *c = &go->components[i];
void gameobject_syncprefabs(char *revertPath)
{
/*
struct gameobject **go = objects;
int i = 0;
while(i != nobjects) {
if ((*go)->editor.curPrefabPath && !strcmp((*go)->editor.curPrefabPath, revertPath)) { ; }//objectRevertPrefab(go); //TODO: revertprefab
}
*/
comp_draw_debug(c);
nuke_nel(5);
if (nuke_btn("Del")) n = i;
if (nuke_push_tree_id(c->ref->name, i)) {
comp_draw_gui(c);
nuke_tree_pop();
}
}
if (n >= 0)
gameobject_delcomponent(go, n);
*/
}
void gameobject_revertprefab(struct gameobject *go)
{
void body_draw_shapes_dbg(cpBody *body, cpShape *shape, void *data) {
struct phys2d_shape *s = cpShapeGetUserData(shape);
s->debugdraw(s->data);
}
void toggleprefab(struct gameobject *go)
{
go->editor.prefabSync = !go->editor.prefabSync;
void gameobject_draw_debug(int go) {
struct gameobject *g = id2go(go);
if (!g || !g->body) return;
if (go->editor.prefabSync) {
strcpy(go->editor.prefabName, go->editor.rootPrefabName);
gameobject_revertprefab(go); //TODO: object revert prefab
} else {
go->editor.prefabName[0] = '\0';
}
cpVect pos = cpBodyGetPosition(g->body);
struct rgba color = {
.r = 0.76*255,
.b = 0.38*255,
.g = 255,
.a = 255
};
draw_cppoint(pos, 3.f, color);
cpBodyEachShape(g->body, body_draw_shapes_dbg, NULL);
}
void gameobject_update(struct gameobject *go)
{
if (go->script)
script_run(go->script);
void gameobject_draw_debugs() {
for (int i = 0; i < arrlen(gameobjects); i++)
gameobject_draw_debug(i);
}
void gameobject_move(struct gameobject *go, float xs, float ys)
{
cpVect p = cpBodyGetPosition(go->body);
p.x += xs * deltaT;
p.y += ys * deltaT;
cpBodySetPosition(go->body, p);
static struct {
struct gameobject go;
cpVect pos;
float angle;
} *saveobjects = NULL;
void gameobject_saveall() {
arrfree(saveobjects);
arrsetlen(saveobjects, arrlen(gameobjects));
for (int i = 0; i < arrlen(gameobjects); i++) {
saveobjects[i].go = gameobjects[i];
saveobjects[i].pos = cpBodyGetPosition(gameobjects[i].body);
saveobjects[i].angle = cpBodyGetAngle(gameobjects[i].body);
}
}
void gameobject_rotate(struct gameobject *go, float as)
{
cpFloat a = cpBodyGetAngle(go->body);
a += as * deltaT;
cpBodySetAngle(go->body, a);
void gameobject_loadall() {
YughInfo("N gameobjects: %d, N saved: %d", arrlen(gameobjects), arrlen(saveobjects));
for (int i = 0; i < arrlen(saveobjects); i++) {
gameobjects[i] = saveobjects[i].go;
cpBodySetPosition(gameobjects[i].body, saveobjects[i].pos);
cpBodySetAngle(gameobjects[i].body, saveobjects[i].angle);
cpBodySetVelocity(gameobjects[i].body, cpvzero);
cpBodySetAngularVelocity(gameobjects[i].body, 0.f);
}
arrfree(saveobjects);
}
void update_gameobjects() {
for (int i = 0; i < arrlen(gameobjects); i++)
gameobject_update(&gameobjects[i]);
}
void object_gui(struct gameobject *go)
{
float temp_pos[2];
temp_pos[0] = cpBodyGetPosition(go->body).x;
temp_pos[1] = cpBodyGetPosition(go->body).y;
draw_point(temp_pos[0], temp_pos[1], 3);
nk_property_float2(ctx, "Position", -1000000.f, temp_pos, 1000000.f, 1.f, 0.5f);
cpVect tvect = { temp_pos[0], temp_pos[1] };
cpBodySetPosition(go->body, tvect);
float mtry = cpBodyGetAngle(go->body);
float modtry = fmodf(mtry * RAD2DEGS, 360.f);
if (modtry < 0.f)
modtry += 360.f;
float modtry2 = modtry;
nk_property_float(ctx, "Angle", -1000.f, &modtry, 1000.f, 0.5f, 0.5f);
modtry -= modtry2;
cpBodySetAngle(go->body, mtry + (modtry * DEG2RADS));
nk_property_float(ctx, "Scale", 0.f, &go->scale, 1000.f, 0.01f, go->scale * 0.01f);
nk_layout_row_dynamic(ctx, 25, 3);
nk_radio_button_label(ctx, "Static", &go->bodytype, CP_BODY_TYPE_STATIC);
nk_radio_button_label(ctx, "Dynamic", &go->bodytype, CP_BODY_TYPE_DYNAMIC);
nk_radio_button_label(ctx, "Kinematic", &go->bodytype, CP_BODY_TYPE_KINEMATIC);
cpBodySetType(go->body, go->bodytype);
if (go->bodytype == CP_BODY_TYPE_DYNAMIC) {
nk_property_float(ctx, "Mass", 0.01f, &go->mass, 1000.f, 0.01f, 0.01f);
cpBodySetMass(go->body, go->mass);
}
nk_property_float(ctx, "Friction", 0.f, &go->f, 10.f, 0.01f, 0.01f);
nk_property_float(ctx, "Elasticity", 0.f, &go->e, 2.f, 0.01f, 0.01f);
int n = -1;
for (int i = 0; i < arrlen(go->components); i++) {
struct component *c = &go->components[i];
if (c->draw_debug)
c->draw_debug(c->data);
nuke_nel(5);
if (nk_button_label(ctx, "Del")) n = i;
if (nk_tree_push_id(ctx, NK_TREE_NODE, c->name, NK_MINIMIZED, i)) {
c->draw_gui(c->data);
nk_tree_pop(ctx);
}
}
if (n >= 0)
gameobject_delcomponent(go, n);
int gameobjects_saved() {
return arrlen(saveobjects);
}

View File

@@ -1,70 +1,70 @@
#ifndef GAMEOBJECT_H
#define GAMEOBJECT_H
#include <stdio.h>
#include "mathc.h"
#include "transform.h"
#include "2dphysics.h"
#include "config.h"
#include <stdbool.h>
#include <chipmunk/chipmunk.h>
#include <stdbool.h>
#include <stdio.h>
#include "quickjs/quickjs.h"
struct shader;
struct sprite;
struct component;
struct editor {
mfloat_t color[3];
int id;
bool active;
bool prefabSync;
char mname[MAXNAME];
char *curPrefabPath;
char prefabName[MAXNAME];
char rootPrefabName[MAXNAME];
};
struct gameobject {
struct mTransform transform;
struct editor editor;
cpBodyType bodytype;
float scale;
float mass;
cpBody *body;
float f; /* friction */
float e; /* elasticity */
struct component *components;
char *script;
cpBodyType bodytype;
int next;
float scale;
float mass;
float f; /* friction */
float e; /* elasticity */
int flipx; /* 1 or -1 */
int flipy;
int sensor;
unsigned int layer;
cpShapeFilter filter;
cpBody *body; /* NULL if this object is dead */
int id;
struct phys_cbs cbs;
struct shape_cb *shape_cbs;
JSValue ref;
};
extern struct gameobject *gameobjects;
struct gameobject *MakeGameobject();
void init_gameobjects();
int MakeGameobject();
void gameobject_apply(struct gameobject *go);
void gameobject_delete(int id);
void clear_gameobjects();
int number_of_gameobjects();
void set_n_gameobjects(int n);
void setup_model_transform(struct mTransform *t, struct shader *s, float scale);
void toggleprefab(struct gameobject *go);
void gameobjects_cleanup();
void gameobject_set_sensor(int id, int sensor);
struct gameobject *get_gameobject_from_id(int id);
void gameobject_save(struct gameobject *go, FILE * file);
void gameobject_addcomponent(struct gameobject *go, struct component *c);
void gameobject_delcomponent(struct gameobject *go, int n);
void gameobject_loadcomponent(struct gameobject *go, int id);
struct gameobject *id2go(int id);
int id_from_gameobject(struct gameobject *go);
int go2id(struct gameobject *go);
int body2id(cpBody *body);
cpBody *id2body(int id);
int shape2gameobject(cpShape *shape);
void gameobject_saveprefab(struct gameobject *go);
void gameobject_makefromprefab(char *path);
void gameobject_syncprefabs(char *revertPath);
void gameobject_revertprefab(struct gameobject *go);
void go_shape_apply(cpBody *body, cpShape *shape, struct gameobject *go);
void gameobject_init(struct gameobject *go, FILE * fprefab);
/* Tries a few methods to select a gameobject; if none is selected returns -1 */
int pos2gameobject(cpVect pos);
void gameobject_update(struct gameobject *go);
void update_gameobjects();
void gameobject_move(struct gameobject *go, float xs, float ys);
void gameobject_move(struct gameobject *go, cpVect vec);
void gameobject_rotate(struct gameobject *go, float as);
void gameobject_setangle(struct gameobject *go, float angle);
void gameobject_setpos(struct gameobject *go, cpVect vec);
void gameobject_draw_debugs();
void gameobject_draw_debug(int go);
void object_gui(struct gameobject *go);
void gameobject_saveall();
void gameobject_loadall();
int gameobjects_saved();
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,135 +1,580 @@
#include "input.h"
#include "ffi.h"
#include "font.h"
#include "nuke.h"
#include "log.h"
#include "script.h"
#include "stb_ds.h"
#include "time.h"
#include <stdio.h>
#include "stb_ds.h"
int32_t mouseWheelX = 0;
int32_t mouseWheelY = 0;
int ychange = 0;
int xchange = 0;
float deltaT = 0;
int quit = 0;
static double c_xpos;
static double c_ypos;
JSValue jsinput;
JSValue jsnum;
JSValue jsgamepadstr[15];
JSValue jsaxesstr[4];
JSValue jsinputstate[5];
JSValue jsaxis;
JSValue jsany;
JSValue jsmouse;
JSValue jspos;
cpVect mouse_pos = {0, 0};
cpVect mouse_delta = {0, 0};
struct joystick {
int id;
GLFWgamepadstate state;
};
static int *downkeys = NULL;
static struct joystick *joysticks = NULL;
static void cursor_pos_cb(GLFWwindow *w, double xpos, double ypos)
{
xchange = (int)xpos - c_xpos;
ychange = (int)ypos - c_ypos;
static int mquit = 0;
c_xpos = xpos;
c_ypos = ypos;
static struct callee pawn_callee;
static struct callee gamepad_callee;
static struct {
char *key;
JSValue value;
} *jshash = NULL;
JSValue input2js(const char *input) {
int idx = shgeti(jshash, input);
if (idx != -1)
return jshash[idx].value;
if (shlen(jshash) == 0)
sh_new_arena(jshash);
JSValue n = str2js(input);
shput(jshash, input, str2js(input));
return n;
}
static void scroll_cb(GLFWwindow *w, double xoffset, double yoffset)
{
mouseWheelY = yoffset;
mouseWheelX = xoffset;
const char *gamepad2str(int btn) {
switch (btn) {
case GLFW_GAMEPAD_BUTTON_CROSS:
return "cross";
case GLFW_GAMEPAD_BUTTON_CIRCLE:
return "circle";
case GLFW_GAMEPAD_BUTTON_SQUARE:
return "square";
case GLFW_GAMEPAD_BUTTON_TRIANGLE:
return "triangle";
case GLFW_GAMEPAD_BUTTON_START:
return "start";
case GLFW_GAMEPAD_BUTTON_LEFT_BUMPER:
return "lbump";
case GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER:
return "rbump";
case GLFW_GAMEPAD_BUTTON_GUIDE:
return "guide";
case GLFW_GAMEPAD_BUTTON_BACK:
return "back";
case GLFW_GAMEPAD_BUTTON_DPAD_UP:
return "dup";
case GLFW_GAMEPAD_BUTTON_DPAD_DOWN:
return "ddown";
case GLFW_GAMEPAD_BUTTON_DPAD_LEFT:
return "dleft";
case GLFW_GAMEPAD_BUTTON_DPAD_RIGHT:
return "dright";
case GLFW_GAMEPAD_BUTTON_LEFT_THUMB:
return "lthumb";
case GLFW_GAMEPAD_BUTTON_RIGHT_THUMB:
return "rthumb";
}
return "NOBTN";
}
void input_init()
{
glfwSetCursorPosCallback(mainwin->window, cursor_pos_cb);
glfwSetScrollCallback(mainwin->window, scroll_cb);
void register_pawn(struct callee c) {
pawn_callee = c;
}
void register_gamepad(struct callee c) {
gamepad_callee = c;
}
void add_downkey(int key) {
for (int i = 0; i < arrlen(downkeys); i++)
if (downkeys[i] == key) return;
arrput(downkeys, key);
}
void rm_downkey(int key) {
for (int i = 0; i < arrlen(downkeys); i++)
if (downkeys[i] == key) {
arrdelswap(downkeys, i);
return;
}
}
static void cursor_pos_cb(GLFWwindow *w, double xpos, double ypos) {
nuke_input_cursor(xpos, ypos);
mouse_delta.x = xpos - mouse_pos.x;
mouse_delta.y = ypos - mouse_pos.y;
mouse_pos.x = xpos;
mouse_pos.y = ypos;
JSValue argv[4];
argv[0] = jsinput;
argv[1] = jsmouse;
argv[2] = jspos;
argv[3] = vec2js(mouse_pos);
script_callee(pawn_callee, 4, argv);
JS_FreeValue(js, argv[3]);
}
static void pawn_call_keydown(int key) {
JSValue argv[4];
argv[0] = jsinput;
argv[1] = jsnum;
argv[2] = jsinputstate[2];
/* TODO: Could cache */
argv[3] = JS_NewInt32(js, key);
script_callee(pawn_callee, 4, argv);
JS_FreeValue(js, argv[3]);
}
static void scroll_cb(GLFWwindow *w, double xoffset, double yoffset) {
mouseWheelY = yoffset;
mouseWheelX = xoffset;
nuke_input_scroll(xoffset, yoffset);
}
static void mb_cb(GLFWwindow *w, int button, int action, int mods) {
nuke_input_button(button, mouse_pos.x, mouse_pos.y, action == GLFW_PRESS);
JSValue argv[3];
argv[0] = jsinput;
switch (action) {
case GLFW_PRESS:
argv[2] = jsinputstate[2];
add_downkey(button);
break;
case GLFW_RELEASE:
rm_downkey(button);
argv[2] = jsinputstate[0];
argv[1] = jsany;
script_callee(pawn_callee, 3, argv);
break;
case GLFW_REPEAT:
argv[2] = jsinputstate[1];
break;
}
argv[1] = input2js(keyname_extd(button, button));
script_callee(pawn_callee, 3, argv);
}
void set_mouse_mode(int mousemode) {
glfwSetInputMode(mainwin->window, GLFW_CURSOR, mousemode);
}
void char_cb(GLFWwindow *w, unsigned int codepoint) {
nuke_input_char(codepoint);
static char out[2] = {0};
static JSValue argv[2];
out[0] = (char)codepoint;
argv[0] = JS_NewString(js, "input_text");
argv[1] = JS_NewString(js, out);
script_callee(pawn_callee, 2, argv);
JS_FreeValue(js, argv[0]);
JS_FreeValue(js, argv[1]);
}
static GLFWcharfun nukechar;
void joystick_add(int id) {
struct joystick joy = {0};
joy.id = id;
arrpush(joysticks, joy);
}
void joystick_cb(int jid, int event) {
YughWarn("IN joystick cb");
if (event == GLFW_CONNECTED) {
for (int i = 0; i < arrlen(joysticks); i++)
if (joysticks[i].id == jid) return;
joystick_add(jid);
} else if (event == GLFW_DISCONNECTED) {
for (int i = 0; i < arrlen(joysticks); i++) {
if (joysticks[i].id == jid) {
arrdelswap(joysticks, i);
return;
}
}
}
}
void input_init() {
glfwSetCursorPosCallback(mainwin->window, cursor_pos_cb);
glfwSetScrollCallback(mainwin->window, scroll_cb);
glfwSetMouseButtonCallback(mainwin->window, mb_cb);
glfwSetJoystickCallback(joystick_cb);
nukechar = glfwSetCharCallback(mainwin->window, char_cb);
char *paddb = slurp_text("data/gamecontrollerdb.txt");
glfwUpdateGamepadMappings(paddb);
free(paddb);
for (int b = 0; b < 15; b++)
jsgamepadstr[b] = str2js(gamepad2str(b));
jsaxesstr[0] = str2js("ljoy");
jsaxesstr[1] = str2js("rjoy");
jsaxesstr[2] = str2js("ltrigger");
jsaxesstr[3] = str2js("rtrigger");
jsaxis = str2js("axis");
/* Grab all joysticks initially present */
for (int i = 0; i < 16; i++)
if (glfwJoystickPresent(i)) joystick_add(i);
jsinputstate[0] = str2js("released");
jsinputstate[1] = str2js("rep");
jsinputstate[2] = str2js("pressed");
jsinputstate[3] = str2js("pressrep");
jsinputstate[4] = str2js("down");
jsinput = str2js("input");
jsnum = str2js("num");
jsany = str2js("any");
jsmouse = str2js("mouse");
jspos = str2js("pos");
}
void input_to_nuke() {
glfwSetCharCallback(mainwin->window, nukechar);
}
void input_to_game() {
glfwSetCharCallback(mainwin->window, char_cb);
}
void call_input_signal(char *signal) {
JSValue s = JS_NewString(js, signal);
JS_Call(js, pawn_callee.fn, pawn_callee.obj, 1, &s);
JS_FreeValue(js, s);
}
char keybuf[50];
const char *keyname_extd(int key, int scancode) {
const char *kkey = NULL;
if (key > 289 && key < 302) {
int num = key - 289;
sprintf(keybuf, "f%d", num);
return keybuf;
} else if (key >= 320 && key <= 329) {
int num = key - 320;
sprintf(keybuf, "kp%d", num);
return keybuf;
} else {
switch (key) {
case GLFW_KEY_ENTER:
kkey = "enter";
break;
case GLFW_KEY_ESCAPE:
kkey = "escape";
break;
case GLFW_KEY_DELETE:
kkey = "delete";
break;
case GLFW_KEY_INSERT:
kkey = "insert";
break;
case GLFW_KEY_TAB:
kkey = "tab";
break;
case GLFW_KEY_RIGHT:
kkey = "right";
break;
case GLFW_KEY_LEFT:
kkey = "left";
break;
case GLFW_KEY_UP:
kkey = "up";
break;
case GLFW_KEY_DOWN:
kkey = "down";
break;
case GLFW_KEY_LEFT_SHIFT:
kkey = "lshift";
break;
case GLFW_KEY_RIGHT_SHIFT:
kkey = "rshift";
break;
case GLFW_KEY_LEFT_CONTROL:
kkey = "lctrl";
break;
case GLFW_KEY_LEFT_ALT:
kkey = "lalt";
break;
case GLFW_KEY_RIGHT_CONTROL:
kkey = "rctrl";
break;
case GLFW_KEY_RIGHT_ALT:
kkey = "ralt";
break;
case GLFW_KEY_SPACE:
kkey = "space";
break;
case GLFW_MOUSE_BUTTON_RIGHT:
kkey = "rmouse";
break;
case GLFW_MOUSE_BUTTON_LEFT:
kkey = "lmouse";
break;
case GLFW_MOUSE_BUTTON_MIDDLE:
kkey = "mmouse";
break;
case GLFW_KEY_KP_ADD:
kkey = "plus";
break;
case GLFW_KEY_KP_SUBTRACT:
kkey = "minus";
break;
case GLFW_KEY_GRAVE_ACCENT:
kkey = "backtick";
break;
case GLFW_KEY_LEFT_BRACKET:
kkey = "lbracket";
break;
case GLFW_KEY_RIGHT_BRACKET:
kkey = "rbracket";
break;
case GLFW_KEY_BACKSPACE:
kkey = "backspace";
break;
}
if (kkey) return kkey;
}
kkey = glfwGetKeyName(key, scancode);
if (kkey) return kkey;
return "NULL";
}
void call_input_down(int *key) {
const char *keyname = glfwGetKeyName(*key, 0);
char keystr[50] = {'\0'};
snprintf(keystr, 50, "input_%s_down", keyname);
script_call(keystr);
JSValue argv[3];
argv[0] = jsinput;
argv[1] = input2js(keyname_extd(*key, *key));
argv[2] = jsinputstate[4];
script_callee(pawn_callee, 3, argv);
}
const char *axis2str(int axis) {
switch (axis) {
case GLFW_GAMEPAD_AXIS_LEFT_X:
return "lx";
case GLFW_GAMEPAD_AXIS_LEFT_Y:
return "ly";
case GLFW_GAMEPAD_AXIS_RIGHT_X:
return "rx";
case GLFW_GAMEPAD_AXIS_RIGHT_Y:
return "ry";
case GLFW_GAMEPAD_AXIS_LEFT_TRIGGER:
return "ltrigger";
case GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER:
return "rtrigger";
}
return "NOAXIS";
}
/* This is called once every frame - or more if we want it more! */
void input_poll(double wait)
{
ychange = 0;
xchange = 0;
mouseWheelX = 0;
mouseWheelY = 0;
void input_poll(double wait) {
mouse_delta = cpvzero;
mouseWheelX = 0;
mouseWheelY = 0;
glfwWaitEventsTimeout(wait);
glfwWaitEventsTimeout(wait);
for (int i = 0; i < arrlen(downkeys); i++)
call_input_down(&downkeys[i]);
//editor_input(&e);
for (int i = 0; i < arrlen(downkeys); i++)
call_input_down(downkeys[i]);
}
for (int i = 0; i < arrlen(joysticks); i++) {
GLFWgamepadstate state;
if (!glfwGetGamepadState(joysticks[i].id, &state)) continue;
void win_key_callback(GLFWwindow *w, int key, int scancode, int action, int mods)
{
char keystr[50] = {'\0'};
strcat(keystr, "input_");
strcat(keystr, glfwGetKeyName(key, 0));
switch (action) {
case GLFW_PRESS:
strcat(keystr, "_pressed");
JSValue argv[4];
argv[0] = num_cache[joysticks[i].id];
for (int b = 0; b < 15; b++) {
argv[1] = jsgamepadstr[b];
int found = 0;
if (state.buttons[b]) {
argv[2] = num_cache[0];
script_callee(gamepad_callee, 3, argv);
for (int i = 0; i < arrlen(downkeys); i++) {
if (downkeys[i] == key)
goto SCRIPTCALL;
}
arrput(downkeys, key);
break;
case GLFW_RELEASE:
strcat(keystr, "_released");
for (int i = 0; i < arrlen(downkeys); i++) {
if (downkeys[i] == key) {
arrdelswap(downkeys, i);
goto SCRIPTCALL;
}
}
break;
case GLFW_REPEAT:
strcat(keystr, "_rep");
break;
}
SCRIPTCALL:
script_call(keystr);
}
void cursor_hide()
{
glfwSetInputMode(mainwin->window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
}
void cursor_show()
{
glfwSetInputMode(mainwin->window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
}
int action_down(int scancode)
{
for (int i = 0; i < arrlen(downkeys); i++) {
if (downkeys[i] == scancode)
return 1;
}
return 0;
}
int action_up(int scancode)
{
int found = 0;
for (int i = 0; i < arrlen(downkeys); i++) {
if (downkeys[i] == scancode) {
found = 1;
break;
if (!joysticks[i].state.buttons[b]) {
argv[2] = num_cache[1];
script_callee(gamepad_callee, 3, argv);
}
} else if (!state.buttons[b] && joysticks[i].state.buttons[b]) {
argv[2] = num_cache[2];
script_callee(gamepad_callee, 3, argv);
}
}
return !found;
argv[2] = jsaxis;
float deadzone = 0.05;
for (int i = 0; i < 4; i++)
state.axes[i] = fabs(state.axes[i]) > deadzone ? state.axes[i] : 0;
argv[1] = jsaxesstr[0];
cpVect v;
v.x = state.axes[0];
v.y = -state.axes[1];
argv[3] = vec2js(v);
script_callee(gamepad_callee, 4, argv);
JS_FreeValue(js, argv[3]);
argv[1] = jsaxesstr[1];
v.x = state.axes[2];
v.y = -state.axes[3];
argv[3] = vec2js(v);
script_callee(gamepad_callee, 4, argv);
JS_FreeValue(js, argv[3]);
argv[1] = jsaxesstr[2];
argv[3] = num2js((state.axes[4] + 1) / 2);
script_callee(gamepad_callee, 4, argv);
JS_FreeValue(js, argv[3]);
argv[1] = jsaxesstr[3];
argv[3] = num2js((state.axes[5] + 1) / 2);
script_callee(gamepad_callee, 4, argv);
JS_FreeValue(js, argv[3]);
joysticks[i].state = state;
}
}
int key_is_num(int key) {
return key <= 57 && key >= 48;
}
void win_key_callback(GLFWwindow *w, int key, int scancode, int action, int mods) {
JSValue argv[3];
argv[0] = jsinput;
argv[1] = input2js(keyname_extd(key, scancode));
switch (action) {
case GLFW_PRESS:
argv[2] = jsinputstate[2];
script_callee(pawn_callee, 3, argv);
argv[2] = jsinputstate[3];
script_callee(pawn_callee, 3, argv);
add_downkey(key);
argv[1] = jsany;
argv[2] = jsinputstate[2];
script_callee(pawn_callee, 3, argv);
if (key_is_num(key))
pawn_call_keydown(key - 48);
break;
case GLFW_RELEASE:
argv[2] = jsinputstate[0];
script_callee(pawn_callee, 3, argv);
rm_downkey(key);
argv[1] = jsany;
script_callee(pawn_callee, 3, argv);
break;
case GLFW_REPEAT:
argv[2] = jsinputstate[1];
script_callee(pawn_callee, 3, argv);
argv[2] = jsinputstate[3];
script_callee(pawn_callee, 3, argv);
break;
}
}
void cursor_hide() {
glfwSetInputMode(mainwin->window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
}
void cursor_show() {
glfwSetInputMode(mainwin->window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
}
int action_down(int scancode) {
for (int i = 0; i < arrlen(downkeys); i++) {
if (downkeys[i] == scancode)
return 1;
}
return 0;
}
int action_up(int scancode) {
int found = 0;
for (int i = 0; i < arrlen(downkeys); i++) {
if (downkeys[i] == scancode) {
found = 1;
break;
}
}
return !found;
}
int want_quit() {
return mquit;
}
void quit() {
YughInfo("Exiting game.");
mquit = 1;
}

View File

@@ -1,30 +1,43 @@
#ifndef INPUT_H
#define INPUT_H
#include <stdint.h>
#include "script.h"
#include "window.h"
#include <chipmunk/chipmunk.h>
#include <stdint.h>
extern int32_t mouseWheelX;
extern int32_t mouseWheelY;
extern int ychange;
extern int xchange;
extern cpVect mouse_pos;
extern cpVect mouse_delta;
extern float deltaT;
extern int quit;
void input_init();
void input_poll(double wait);
void cursor_hide();
void cursor_show();
void set_mouse_mode(int mousemode);
void call_input_signal(char *signal);
const char *keyname_extd(int key, int scancode);
int action_down(int scancode);
void register_pawn(struct callee c);
void register_gamepad(struct callee c);
int want_quit();
void quit();
void win_key_callback(GLFWwindow *w, int key, int scancode, int action, int mods);
struct inputaction
{
int scancode;
struct inputaction {
int scancode;
};
void input_to_nuke();
void input_to_game();
#endif

View File

@@ -1,54 +1,49 @@
#include "level.h"
#include <stdio.h>
#include <string.h>
#include "gameobject.h"
#include "resources.h"
#include <stdio.h>
#include <string.h>
#include "stb_ds.h"
void save_level(char name[MAXNAME])
{
FILE *lfile = res_open(name, "wb+");
void save_level(char name[MAXNAME]) {
FILE *lfile = res_open(name, "wb+");
if (!lfile) return;
if (!lfile) return;
int objs = arrlen(gameobjects);
fwrite(&objs, sizeof(objs), 1, lfile);
int objs = arrlen(gameobjects);
fwrite(&objs, sizeof(objs), 1, lfile);
for (int i = 0; i < objs; i++)
gameobject_save(&gameobjects[i], lfile);
fclose(lfile);
fclose(lfile);
}
void load_level(char name[MAXNAME])
{
FILE *lfile = fopen(name, "rb");
void load_level(char name[MAXNAME]) {
/*
FILE *lfile = fopen(name, "rb");
if (!lfile) return;
if (!lfile) return;
new_level();
new_level();
int objs;
fread(&objs, sizeof(objs), 1, lfile);
int objs;
fread(&objs, sizeof(objs), 1, lfile);
arraddn(gameobjects, objs);
arraddn(gameobjects, objs);
for (int i = 0; i < objs; i++) {
struct gameobject *go = &gameobjects[i];
fread(go, sizeof(struct gameobject), 1, lfile);
go->components = NULL;
gameobject_init(go, lfile);
}
for (int i = 0; i < objs; i++) {
struct gameobject *go = &gameobjects[i];
fread(go, sizeof(struct gameobject), 1, lfile);
go->components = NULL;
gameobject_init(go, lfile);
}
fclose(lfile);
fclose(lfile);
*/
}
void new_level()
{
for (int i = 0; i < arrlen(gameobjects); i++)
gameobject_delete(i);
void new_level() {
for (int i = 0; i < arrlen(gameobjects); i++)
gameobject_delete(i);
arrfree(gameobjects);
arrfree(gameobjects);
}

View File

@@ -6,12 +6,11 @@
// This class holds all of the entities and options for a level. Really it's nothing more than a container and access point for all the entities currently loaded into the game.
struct level {
char name[MAXNAME];
char name[MAXNAME];
};
void save_level(char name[MAXNAME]);
void load_level(char name[MAXNAME]);
void new_level();
#endif

View File

@@ -1,66 +0,0 @@
#include "log.h"
#include "render.h"
#include <time.h>
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
#define logLevel 0
//char *logstr[] = { "INFO", "WARN", "\x1b[1;31mERROR\x1b[0m", "CRITICAL" };
char *logstr[] = { "INFO", "WARN", "ERROR", "CRITICAL" };
char *catstr[] = {"ENGINE"};
FILE *fout = NULL;
void mYughLog(int category, int priority, int line, const char *file, const char *message, ...)
{
if (priority >= logLevel) {
time_t now = time(0);
char *dt = ctime(&now);
dt[strlen(dt) - 1] = '\0'; // The above time conversion adds a \n; this removes it
va_list args;
va_start(args, message);
char msgbuffer[ERROR_BUFFER] = { '\0' };
vsnprintf(msgbuffer, ERROR_BUFFER, message, args);
va_end(args);
char buffer[ERROR_BUFFER] = { '\0' };
snprintf(buffer, ERROR_BUFFER, "%s | %s | %s [ %s:%d ] %s\n", logstr[priority], catstr[0], dt, file, line, msgbuffer);
printf("%s", buffer);
fflush(stdout);
if (fout) {
fprintf(fout, "%s", buffer);
fflush(fout);
}
}
}
void log_setfile(char *file) {
YughInfo("Opening output log %s.", file);
fout = fopen(file, "w");
}
void log_cat(FILE *f) {
char out[1024];
while (fgets(out, sizeof(out), f)) {
out[strcspn(out, "\n")] = '\0';
YughInfo(out);
}
}
void FlushGLErrors()
{
GLenum glErr = GL_NO_ERROR;
glErr = glGetError();
while (glErr != GL_NO_ERROR) {
YughLog(0, 3,
"GL Error: %d", glErr);
glErr = glGetError();
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,132 +0,0 @@
#include "mesh.h"
#include "render.h"
#include "shader.h"
#include "texture.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void DrawMesh(struct mesh *mesh, struct shader *shader)
{
// bind appropriate textures
uint32_t diffuseNr = 1;
uint32_t specularNr = 1;
uint32_t normalNr = 1;
uint32_t heightNr = 1;
for (int i = 0; i < (mesh->te - mesh->textures); i++) {
glActiveTexture(GL_TEXTURE0 + i); // active proper texture unit before binding
// retrieve texture number (the N in diffuse_textureN)
char number = 0;
// TODO: malloc every single frame ... nope! Change to stack
/*char *name =
(char *) malloc(sizeof(char) *
(strlen(mesh->textures[i].type) + 2));*/
if (mesh->textures[i].type == TEX_DIFF)
number = diffuseNr++;
else if (mesh->textures[i].type == TEX_SPEC)
number = specularNr++;
else if (mesh->textures[i].type == TEX_NORM)
number = normalNr++;
else if (mesh->textures[i].type == TEX_HEIGHT)
number = heightNr++;
/*
glUniform1i(glGetUniformLocation(shader->id, name), i);
glBindTexture(GL_TEXTURE_2D, mesh->textures[i].id);
free(name);
*/
}
// draw mesh
glBindVertexArray(mesh->VAO);
DrawMeshAgain(mesh);
// DEBUG
// triCount += indices.size() / 3;
}
void DrawMeshAgain(struct mesh *mesh)
{
glDrawElements(GL_TRIANGLES, (mesh->ie - mesh->indices),
GL_UNSIGNED_INT, 0);
}
struct mesh *MakeMesh(struct Vertex *vertices, struct Vertex *ve,
uint32_t * indices, uint32_t * ie,
struct Texture *textures, struct Texture *te)
{
struct mesh *newmesh = (struct mesh *) malloc(sizeof(struct mesh));
newmesh->vertices = vertices;
newmesh->ve = ve;
newmesh->indices = indices;
newmesh->ie = ie;
newmesh->textures = textures;
newmesh->te = te;
setupmesh(newmesh);
return newmesh;
}
void setupmesh(struct mesh *mesh)
{
// create buffers/arrays
glGenVertexArrays(1, &mesh->VAO);
glGenBuffers(1, &mesh->VBO);
glGenBuffers(1, &mesh->EBO);
glBindVertexArray(mesh->VAO);
// load data into vertex buffers
glBindBuffer(GL_ARRAY_BUFFER, mesh->VBO);
// The effect is that we can simply pass a pointer to the struct and it translates perfectly to vevc array which
// again translates to 3/2 floats which translates to a byte array.
glBufferData(GL_ARRAY_BUFFER,
(mesh->ve - mesh->vertices) * sizeof(struct Vertex),
&mesh->vertices[0], GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
(mesh->ie - mesh->indices) * sizeof(uint32_t),
&mesh->indices[0], GL_STATIC_DRAW);
// set the vertex attribute pointers
// vertex Positions
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(struct Vertex),
(void *) 0);
// vertex normals
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(struct Vertex),
(void *) offsetof(struct Vertex, Normal[3]));
// vertex texture coords
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(struct Vertex),
(void *) offsetof(struct Vertex, TexCoords[2]));
// vertex tangent
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(struct Vertex),
(void *) offsetof(struct Vertex, Tangent[3]));
// vertex bitangent
glEnableVertexAttribArray(4);
glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, sizeof(struct Vertex),
(void *) offsetof(struct Vertex, Bitangent[3]));
// Bone ids
glEnableVertexAttribArray(5);
glVertexAttribPointer(5, 4, GL_INT, GL_FALSE, sizeof(struct Vertex),
(void *) offsetof(struct Vertex,
m_BoneIDs
[MAX_BONE_INFLUENCE]));
// Weights
glEnableVertexAttribArray(6);
glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, sizeof(struct Vertex),
(void *) offsetof(struct Vertex, m_Weights));
glBindVertexArray(0);
}

View File

@@ -1,41 +0,0 @@
#ifndef MESH_H
#define MESH_H
#include "mathc.h"
#include <stdint.h>
struct shader;
struct Texture;
#define MAX_BONE_INFLUENCE 4
struct Vertex {
mfloat_t Position[3];
mfloat_t Normal[3];
mfloat_t TexCoords[2];
mfloat_t Tangent[3];
mfloat_t Bitangent[3];
int m_BoneIDs[MAX_BONE_INFLUENCE];
float m_Weights[MAX_BONE_INFLUENCE];
};
struct mesh {
struct Vertex *vertices;
struct Vertex *ve;
uint32_t *indices;
uint32_t *ie;
struct Texture *textures;
struct Texture *te;
uint32_t VAO, VBO, EBO;
};
struct mesh *MakeMesh(struct Vertex *vertices, struct Vertex *ve,
uint32_t * indices, uint32_t * ie,
struct Texture *textures, struct Texture *te);
void setupmesh(struct mesh *mesh); /* Loads mesh into the GPU */
void DrawMesh(struct mesh *mesh, struct shader *shader);
void DrawMeshAgain(struct mesh *mesh); /* Draws whatever mesh was drawn last */
#endif

92927
source/engine/miniaudio.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,40 +0,0 @@
#include "mix.h"
#include "stddef.h"
#include "time.h"
#include "sound.h"
static struct bus bus[256];
short mastermix[BUF_FRAMES*CHANNELS];
struct bus *first_free_bus(struct dsp_filter in) {
for (int i = 0; i < 256; i++) {
if (!bus[i].on) {
bus[i].on = 1;
bus[i].in = in;
return &bus[i];
}
}
return NULL;
}
void bus_free(struct bus *bus)
{
bus->on = 0;
}
void bus_fill_buffers(short *master, int n) {
for (int i = 0; i < 256; i++) {
if (bus[i].on != 1) continue;
dsp_run(bus[i].in, bus[i].buf, BUF_FRAMES);
}
memset(master, 0, BUF_FRAMES*CHANNELS*sizeof(short));
for (int j = 0; j < 256; j++) {
if (!bus[j].on) continue;
for (int i = 0; i < BUF_FRAMES*CHANNELS; i++) {
master[i] += bus[j].buf[i];
}
}
}

View File

@@ -1,282 +0,0 @@
#include "model.h"
#include "mesh.h"
#include "resources.h"
#include "shader.h"
#include <cgltf.h>
#include <string.h>
#include <stdlib.h>
#include "log.h"
static struct model *lastRendered;
static struct model *loadedModels[100];
static struct model **lastModel = loadedModels;
static void processnode();
static void processmesh();
static void processtexture();
struct model *GetExistingModel(const char *path)
{
struct model **model = loadedModels;
while (model++ != lastModel) {
if (!strcmp(path, (*model)->path))
goto end;
return MakeModel(path);
}
end:
return NULL;
}
/* TODO: Make this a hash compare for speedup */
struct model *MakeModel(const char *path)
{
char *modelPath =
(char *) malloc(sizeof(char) *
(strlen(DATA_PATH) + strlen(path) + 1));
modelPath[0] = '\0';
strcat(modelPath, DATA_PATH);
strcat(modelPath, path);
printf
("Created new model with modelPath %s, from data_path %s and path %s\n",
modelPath, DATA_PATH, path);
struct model *newmodel =
(struct model *) malloc(sizeof(struct model));
newmodel->path = path;
loadmodel(newmodel);
*lastModel++ = newmodel;
return newmodel;
}
// TODO: Come back to this; simple optimization
void draw_model(struct model *model, struct shader *shader)
{
if (lastRendered != model) {
lastRendered = model;
for (int i = 0; i < (model->mp - model->meshes); i++)
DrawMesh(&model->meshes[i], shader);
} else {
for (uint32_t i = 0; i < (model->mp - model->meshes); i++)
DrawMeshAgain(&model->meshes[i]);
}
}
void loadmodel(struct model *model)
{
YughInfo("Loading model at path %s", model->path);
/*
// Load model with cgltf
cgltf_options options = {0};
cgltf_data *data = NULL;
cgltf_result result = cgltf_parse_file(&options, model->path, &data);
meshes = (struct mesh*)malloc(sizeof(Mesh)*cgltf_data->meshes_count);
directory = get_directory_from_path(model->path);
for (int i = 0; i < data->nodes_count; i++) {
if (data->nodes[i]->mesh) {
for (int j = 0; j < data->nodes[i]->mesh->primatives_count; j++) {
for (int k = 0; k < data->nodes[i]->mesh->primatives[j]->attributes_count; k++) {
switch(data->nodes[i]->mesh->primatives[j]->attributes[k]->type) {
case cgltf_attribute_type_position:
Vertex *vs = (Vertex*)malloc(sizeof(Vertex) * cgltf_accessor_unpack_floats(:::attributes[k]->accesor, NULL, attributes[k]->accessor.count);
cgltf_accessor_unpack_floats(:::attributes[k]->accessor, vs, attributes[k]->accessor.count);
break;
case cgltf_attribute_type_normal:
break;
case cgltf_attribute_type_tangent:
break;
case cgltf_attribute_type_texcoord:
break;
}
}
}
}
}
}
*/
/* TODO: DELETE
// read file via ASSIMP
Assimp::Importer importer;
const aiScene *scene = importer.ReadFile(path,
aiProcess_Triangulate |
aiProcess_GenSmoothNormals |
aiProcess_FlipUVs |
aiProcess_CalcTangentSpace);
// check for errors
if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE
|| !scene->mRootNode) {
YughLog(0, SDL_LOG_PRIORITY_ERROR,
"ASSIMP error: %s",
importer.GetErrorString());
return;
}
directory = get_directory_from_path(path);
meshes = (Mesh *) malloc(sizeof(Mesh) * 100);
mp = meshes;
// process ASSIMP's root node recursively
processNode(scene->mRootNode, scene); */
}
static void processnode()
{
/*
for (uint32_t i = 0; i < node->mNumMeshes; i++) {
aiMesh *mesh = scene->mMeshes[node->mMeshes[i]];
*mp = processMesh(mesh, scene);
mp++;
}
for (uint32_t i = 0; i < node->mNumChildren; i++) {
processnode(node->mChildren[i], scene);
}
*/
}
static void processmesh()
{
/*
Vertex *vertices =
(Vertex *) malloc(sizeof(Vertex) * mesh->mNumVertices);
Vertex *vp = vertices + mesh->mNumVertices;
Vertex *p = vertices;
for (int i = 0; i < mesh->mNumVertices; i++) {
// positions
(p + i)->Position.x = mesh->mVertices[i][0];
(p + i)->Position.y = mesh->mVertices[i][1];
(p + i)->Position.z = mesh->mVertices[i][2];
// normals
if (mesh->HasNormals()) {
(p + i)->Normal.x = mesh->mNormals[i][0];
(p + i)->Normal.y = mesh->mNormals[i].y;
(p + i)->Normal.z = mesh->mNormals[i].z;
}
// texture coordinates
if (mesh->mTextureCoords[0]) {
glm::vec2 vec;
// a vertex can contain up to 8 different texture coordinates. We thus make the assumption that we won't
// use models where a vertex can have multiple texture coordinates so we always take the first set (0).
(p + i)->TexCoords.x = mesh->mTextureCoords[0][i].x;
(p + i)->TexCoords.y = mesh->mTextureCoords[0][i].y;
// tangent
(p + i)->Tangent.x = mesh->mTangents[i].x;
(p + i)->Tangent.y = mesh->mTangents[i].y;
(p + i)->Tangent.z = mesh->mTangents[i].z;
// bitangent
(p + i)->Bitangent.x = mesh->mBitangents[i].x;
(p + i)->Bitangent.y = mesh->mBitangents[i].y;
(p + i)->Bitangent.z = mesh->mBitangents[i].z;
} else
(p + i)->TexCoords = glm::vec2(0.0f, 0.0f);
}
// TODO: Done quickly, find better way. Go through for loop twice!
int numindices = 0;
// now walk through each of the mesh's faces (a face is a mesh its triangle) and retrieve the corresponding vertex indices.
for (uint32_t i = 0; i < mesh->mNumFaces; i++) {
numindices += mesh->mFaces[i].mNumIndices;
}
uint32_t *indices = (uint32_t *) malloc(sizeof(uint32_t) * numindices);
uint32_t *ip = indices;
for (uint32_t i = 0; i < mesh->mNumFaces; i++) {
for (uint32_t j = 0; j < mesh->mFaces[i].mNumIndices; j++) {
*ip = mesh->mFaces[i].mIndices[j];
ip++;
}
}
// std::vector<Texture> textures;
aiMaterial *material = scene->mMaterials[mesh->mMaterialIndex];
// TODO: Allocating 100 to be safe, can probably be way less
textures_loaded = (Texture *) malloc(sizeof(Texture) * 100);
tp = textures_loaded;
// we assume a convention for sampler names in the shaders. Each diffuse texture should be named
// as 'texture_diffuseN' where N is a sequential number ranging from 1 to MAX_SAMPLER_NUMBER.
// Same applies to other texture as the following list summarizes:
// diffuse: texture_diffuseN
// specular: texture_specularN
// normal: texture_normalN
// 1. diffuse maps
loadMaterialTextures(material, aiTextureType_DIFFUSE,
"texture_diffuse");
// 2. specular maps
loadMaterialTextures(material, aiTextureType_SPECULAR,
"texture_specular");
// 3. normal maps
loadMaterialTextures(material, aiTextureType_NORMALS,
"texture_normal");
// 4. height maps
loadMaterialTextures(material, aiTextureType_AMBIENT,
"texture_height");
// return a mesh object created from the extracted mesh data
return Mesh(vertices, vp, indices, ip, textures_loaded, tp);
*/
}
// TODO: This routine mallocs inside the function
static void processtexture()
{
/*
for (uint32_t i = 0; i < mat->GetTextureCount(type); i++) {
aiString str;
mat->GetTexture(type, i, &str);
for (Texture * tpp = textures_loaded; tpp != tp; tpp++) {
if (strcmp(tpp->path, str.data) == 0)
goto next; // Check if we already have this texture
}
tp->id = TextureFromFile(str.data, this->directory);
tp->type = (char *) malloc(sizeof(char) * strlen(typeName));
strcpy(tp->type, typeName);
tp->path = (char *) malloc(sizeof(char) * strlen(str.data));
strcpy(tp->path, str.data);
tp++;
next:;
}
*/
}

View File

@@ -1,219 +0,0 @@
#include "mrbffi.h"
#include "s7.h"
#include "font.h"
#include "script.h"
#include "string.h"
#include "window.h"
#include "editor.h"
#include "engine.h"
#include "log.h"
#include "nuke.h"
/* FFI */
s7_pointer s7_ui_label(s7_scheme *sc, s7_pointer args) {
if (s7_is_string(s7_car(args))) {
nuke_label(s7_string(s7_car(args)));
return s7_make_boolean(sc, 1);
}
return s7_wrong_type_arg_error(sc, "ui_label", 1, args, "Should be a string.");
}
s7_pointer s7_ui_btn(s7_scheme *sc, s7_pointer args) {
return s7_make_boolean(sc, nuke_btn(s7_string(s7_car(args))));
}
s7_pointer s7_ui_nel(s7_scheme *sc, s7_pointer args) {
nuke_nel(s7_integer(s7_cadr(args)));
return s7_make_boolean(sc, 1);
}
s7_pointer s7_ui_prop(s7_scheme *sc, s7_pointer args) {
float val = s7_real(s7_cadr(args));
nuke_prop_float(s7_string(s7_car(args)), (float)s7_real(s7_caddr(args)), &val, s7_real(s7_cadddr(args)), s7_real(s7_car(s7_cddddr(args))), s7_real(s7_car(s7_cdr(s7_cddddr(args)))));
return s7_make_real(sc, val);
}
s7_pointer s7_ui_text(s7_scheme *sc, s7_pointer args) {
const char *s = s7_string(s7_car(args));
int len = s7_integer(s7_cadr(args));
char str[len+1];
strncpy(str,s,len);
nuke_edit_str(str);
return s7_make_string(sc, str);
}
/*
mrb_value mrb_ui_begin(mrb_state *mrb, mrb_value self) {
char *title;
mrb_float w, h;
mrb_get_args(mrb, "zff", &title, &w, &h);
return mrb_bool_value(nk_begin(ctx, title, nk_rect(0,0,w,h), NK_WINDOW_TITLE|NK_WINDOW_BORDER|NK_WINDOW_SCALABLE|NK_WINDOW_MOVABLE|NK_WINDOW_NO_SCROLLBAR));
}
*/
/*
mrb_value mrb_ui_rendertext(mrb_state *mrb, mrb_value self) {
char *s;
mrb_float pos[2];
mrb_float size, ol;
mrb_get_args(mrb, "zffff", &s, &pos[0], &pos[1], &size, &ol);
static float white[3] = {1.f, 1.f, 1.f};
float fpos[2] = {(float)pos[0], (float)pos[1]};
renderText(s, fpos, size, white, ol);
return self;
}
mrb_value mrb_win_make(mrb_state *mrb, mrb_value self) {
char name[50] = "New Window";
struct window *new = MakeSDLWindow(name, 500, 500, 0);
return mrb_float_value(mrb, new->id);
}
mrb_value mrb_win_cmd(mrb_state *mrb, mrb_value self) {
mrb_float win, cmd;
mrb_get_args(mrb, "ff", &win, &cmd);
struct window *new = window_i(win);
switch ((int)cmd)
{
case 0: // toggle fullscreen
window_togglefullscreen(new);
break;
case 1: // Fullscreen on
window_makefullscreen(new);
break;
case 2: // Fullscreen off
window_unfullscreen(new);
break;
}
return self;
}
mrb_value mrb_nuke_cb(mrb_state *mrb, mrb_value self) {
mrb_float win;
mrb_sym cb;
mrb_get_args(mrb, "fn", &win, &cb);
window_i((int)win)->nuke_cb = cb;
return self;
}
mrb_value mrb_gui_cb(mrb_state *mrb, mrb_value self) {
mrb_float win;
mrb_sym cb;
mrb_get_args(mrb, "fn", &win, &cb);
window_i((int)win)->gui_cb = cb;
return self;
}
mrb_value mrb_sound_make(mrb_state *mrb, mrb_value self) {
mrb_value vals;
mrb_get_args(mrb, "H", &vals);
char *name = mrb_str_to_cstr(mrb, mrb_hash_fetch(mrb, vals, mrb_symbol_value(mrb_intern_cstr(mrb, "name")), mrb_str_new_cstr(mrb, "New Window")));
YughInfo("Window name is %s.", name);
return self;
}
mrb_value mrb_sound_cmd(mrb_state *mrb, mrb_value self) {
mrb_float sound, cmd;
mrb_get_args(mrb, "ff", &sound, &cmd);
switch ((int)cmd)
{
case 0: // play
break;
case 1: // pause
break;
case 2: // stop
break;
case 3: // play from beginning
break;
}
return self;
}
mrb_value mrb_settings_cmd(mrb_state *mrb, mrb_value self) {
mrb_float cmd, val;
mrb_get_args(mrb, "ff", &cmd, &val);
switch((int)cmd)
{
case 0: // render fps
renderMS = (double)val;
break;
case 1:
updateMS = (double)val;
break;
case 2:
physMS = (double)val;
break;
}
return self;
}
mrb_value mrb_editor_render(mrb_state *mrb, mrb_value self) {
editor_render();
return self;
}
*/
//#define MRB_FUNC(NAME, ARGS) mrb_define_method(mrb, mrb->object_class, #NAME, mrb_ ## NAME, ARGS)
#define S7_FUNC(NAME, ARGS) s7_define_function(s7, #NAME, s7_ ##NAME, ARGS, 0, 0, "")
void ffi_load() {
//s7_define_function(s7, "ui_label", s7_ui_label, 1, 0, 0, "Draw UI label with given string");
S7_FUNC(ui_label, 1);
S7_FUNC(ui_btn, 1);
S7_FUNC(ui_nel, 1);
S7_FUNC(ui_prop, 6);
S7_FUNC(ui_text, 2);
/*
MRB_FUNC(load, MRB_ARGS_REQ(1));
MRB_FUNC(ui_label, MRB_ARGS_REQ(1));
MRB_FUNC(ui_btn, MRB_ARGS_REQ(1));
MRB_FUNC(ui_nel, MRB_ARGS_REQ(2));
MRB_FUNC(ui_begin, MRB_ARGS_REQ(3));
MRB_FUNC(ui_prop, MRB_ARGS_REQ(6));
MRB_FUNC(ui_text, MRB_ARGS_REQ(2));
MRB_FUNC(ui_rendertext, MRB_ARGS_REQ(5));
MRB_FUNC(c_reload, MRB_ARGS_REQ(1));
MRB_FUNC(win_make, MRB_ARGS_REQ(1));
MRB_FUNC(win_cmd, MRB_ARGS_REQ(2));
MRB_FUNC(nuke_cb, MRB_ARGS_REQ(2));
MRB_FUNC(gui_cb, MRB_ARGS_REQ(2));
MRB_FUNC(sound_make, MRB_ARGS_REQ(1));
MRB_FUNC(sound_cmd, MRB_ARGS_REQ(2));
MRB_FUNC(editor_render, MRB_ARGS_REQ(0));
MRB_FUNC(settings_cmd, MRB_ARGS_REQ(2));
*/
}

View File

@@ -1,6 +0,0 @@
#ifndef MRBFFI_H
#define MRBFFI_H
void ffi_load();
#endif

View File

@@ -1,94 +1,177 @@
#define NK_INCLUDE_FIXED_TYPES
#define NK_INCLUDE_STANDARD_IO
#define NK_INCLUDE_STANDARD_VARARGS
#define NK_INCLUDE_DEFAULT_ALLOCATOR
#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
#define NK_INCLUDE_FONT_BAKING
#define NK_INCLUDE_DEFAULT_FONT
#define NK_INCLUDE_STANDARD_BOOL
#define NK_IMPLEMENTATION
#define NK_GLFW_GL3_IMPLEMENTATION
#define NK_KEYSTATE_BASED_INPUT
#include "nuke.h"
#include "nuklear_glfw_gl3.h"
#define STBTT_STATIC
#include "nuke.h"
#define SOKOL_GLCORE33
#include "sokol/sokol_gfx.h"
#define SOKOL_NUKLEAR_NO_SOKOL_APP
#define SOKOL_NUKLEAR_IMPL
#include "sokol/sokol_nuklear.h"
#include <stdarg.h>
#include "log.h"
#include "texture.h"
#include "window.h"
#define MAX_VERTEX_BUFFER 512 * 1024
#define MAX_ELEMENT_BUFFER 128 * 1024
struct nk_context *ctx;
static struct nk_glfw nkglfw = {0};
//static struct nk_glfw nkglfw = {0};
void nuke_init(struct window *win) {
window_makecurrent(win);
window_makecurrent(win);
snk_setup(&(snk_desc_t){
.no_default_font = false
});
ctx = nk_glfw3_init(&nkglfw, win->window, NK_GLFW3_INSTALL_CALLBACKS);
struct nk_font_atlas *atlas;
nk_glfw3_font_stash_begin(&nkglfw, &atlas);
struct nk_font *noto = nk_font_atlas_add_from_file(atlas, "fonts/notosans.tff", 14, 0);
nk_glfw3_font_stash_end(&nkglfw);
ctx = snk_new_frame();
}
void nuke_start()
void nuke_start() {
ctx = snk_new_frame();
}
void nuke_input_cursor(int x, int y)
{
nk_glfw3_new_frame(&nkglfw);
nk_input_motion(ctx, x, y);
}
void nuke_end()
void nuke_input_key(int key, int down)
{
nk_glfw3_render(&nkglfw, NK_ANTI_ALIASING_ON, MAX_VERTEX_BUFFER, MAX_ELEMENT_BUFFER);
nk_input_key(ctx, key, down);
}
void nk_property_float3(struct nk_context *ctx, const char *label, float min, float *val, float max, float step, float dragstep) {
nk_layout_row_dynamic(ctx, 25, 1);
nk_label(ctx, label, NK_TEXT_LEFT);
nk_layout_row_dynamic(ctx, 25, 3);
nk_property_float(ctx, "#X", min, &val[0], max, step, dragstep);
nk_property_float(ctx, "#Y", min, &val[1], max, step, dragstep);
nk_property_float(ctx, "#Z", min, &val[2], max, step, dragstep);
void nuke_input_button(int btn, int x, int y, int down)
{
nk_input_button(ctx, btn, x, y, down);
}
void nk_property_float2(struct nk_context *ctx, const char *label, float min, float *val, float max, float step, float dragstep) {
nk_layout_row_dynamic(ctx, 25, 1);
nk_label(ctx, label, NK_TEXT_LEFT);
nk_layout_row_dynamic(ctx, 25, 2);
nk_property_float(ctx, "#X", min, &val[0], max, step, dragstep);
nk_property_float(ctx, "#Y", min, &val[1], max, step, dragstep);
void nuke_input_scroll(float x, float y)
{
nk_input_scroll(ctx, nk_vec2(x, y));
}
void nuke_input_char(char c)
{
nk_input_char(ctx, c);
}
void nuke_input_begin() { nk_input_begin(ctx); }
void nuke_input_end() { nk_input_end(ctx); }
void nuke_end() {
snk_render(1200,720);
}
int nuke_begin(const char *lbl, struct nk_rect rect, int flags) {
return nk_begin(ctx, lbl, rect, flags);
}
int nuke_begin_win(const char *lbl) {
return nk_begin(ctx, lbl, nk_rect(10, 10, 400, 600), NK_WINDOW_BORDER | NK_WINDOW_MOVABLE | NK_WINDOW_SCALABLE | NK_WINDOW_TITLE);
}
void nuke_stop() {
nk_end(ctx);
}
struct nk_rect nuke_win_get_bounds() {
return nk_window_get_bounds(ctx);
}
void nuke_row(int height) {
nk_layout_row_dynamic(ctx, height, 1);
}
void nuke_property_float3(const char *label, float min, float *val, float max, float step, float dragstep) {
nk_layout_row_dynamic(ctx, 25, 1);
nk_label(ctx, label, NK_TEXT_LEFT);
nk_layout_row_dynamic(ctx, 25, 3);
nuke_property_float("#X", min, &val[0], max, step, dragstep);
nuke_property_float("#Y", min, &val[1], max, step, dragstep);
nuke_property_float("#Z", min, &val[2], max, step, dragstep);
}
void nuke_property_float2(const char *label, float min, float *val, float max, float step, float dragstep) {
nk_layout_row_dynamic(ctx, 25, 1);
nk_label(ctx, label, NK_TEXT_LEFT);
nk_layout_row_dynamic(ctx, 25, 2);
nuke_property_float("#X", min, &val[0], max, step, dragstep);
nuke_property_float("#Y", min, &val[1], max, step, dragstep);
}
void nuke_property_float(const char *lbl, float min, float *val, float max, float step, float dragstep) {
nk_property_float(ctx, lbl, min, val, max, step, dragstep);
}
int nuke_btn(const char *lbl) {
return nk_button_label(ctx, lbl);
return nk_button_label(ctx, lbl);
}
void nuke_img(char *path) {
/*
struct Texture *t = texture_pullfromfile(path);
nk_layout_row_static(ctx, t->height, t->width, 1);
nk_image(ctx, nk_image_id(t->id));
*/
}
void nuke_property_int(const char *lbl, int min, int *val, int max, int step) {
nk_property_int(ctx, lbl, min, val, max, step, step);
}
void nk_radio_button_label(struct nk_context *ctx, const char *label, int *val, int cmp) {
if (nk_option_label(ctx, label, *val == cmp)) *val = cmp;
nk_property_int(ctx, lbl, min, val, max, step, step);
}
void nuke_radio_btn(const char *lbl, int *val, int cmp) {
//nk_radio_button_label(ctx, lbl, val, cmp);
if (nk_option_label(ctx, lbl, *val==cmp)) *val = cmp;
if (nk_option_label(ctx, lbl, *val == cmp)) *val = cmp;
}
void nuke_checkbox(const char *lbl, int *val) {
nk_checkbox_label(ctx, lbl, val);
nk_checkbox_label(ctx, lbl, val);
}
void nuke_scrolltext(char *str) {
nk_edit_string_zero_terminated(ctx, NK_EDIT_MULTILINE | NK_EDIT_GOTO_END_ON_ACTIVATE, str, 1024 * 1024 * 5, NULL);
}
void nuke_nel(int cols) {
nk_layout_row_dynamic(ctx, 25, cols);
nk_layout_row_dynamic(ctx, 25, cols);
}
void nuke_nel_h(int cols, int h) {
nk_layout_row_dynamic(ctx, h, cols);
}
void nuke_label(const char *s) {
nk_label(ctx, s, NK_TEXT_LEFT);
nk_label(ctx, s, NK_TEXT_LEFT);
}
void nuke_edit_str(char *str) {
nk_edit_string_zero_terminated(ctx, NK_EDIT_BOX|NK_EDIT_NO_HORIZONTAL_SCROLL, str, 130, nk_filter_ascii);
}
nk_edit_string_zero_terminated(ctx, NK_EDIT_BOX | NK_EDIT_NO_HORIZONTAL_SCROLL, str, 130, nk_filter_ascii);
}
int nuke_push_tree_id(const char *name, int id) {
return nk_tree_push_id(ctx, NK_TREE_NODE, name, NK_MINIMIZED, id);
}
void nuke_tree_pop() {
nk_tree_pop(ctx);
}
void nuke_labelf(const char *fmt, ...) {
char buf[512];
va_list args;
va_start(args, fmt);
vsnprintf(buf, 512, fmt, args);
nuke_label(buf);
va_end(args);
}

View File

@@ -1,32 +1,59 @@
#ifndef NUKE_H
#define NUKE_H
#define NK_INCLUDE_FIXED_TYPES
#define NK_INCLUDE_FIXED_TYPES
#define NK_INCLUDE_STANDARD_VARARGS
#define NK_INCLUDE_FONT_BAKING
#define NK_INCLUDE_DEFAULT_FONT
#define NK_INCLUDE_STANDARD_BOOL
#define NK_INCLUDE_DEFAULT_ALLOCATOR
#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
#include "nuklear.h"
extern struct nk_context *ctx;
struct window;
void nuke_init(struct window *win);
void nuke_start();
void nuke_end();
void nk_property_float3(struct nk_context *ctx, const char *label, float min, float *val, float max, float step, float dragstep);
void nk_property_float2(struct nk_context *ctx, const char *label, float min, float *val, float max, float step, float dragstep);
int nuke_begin(const char *lbl, struct nk_rect rect, int flags);
int nuke_begin_win(const char *lbl);
void nuke_stop();
struct nk_rect nuke_win_get_bounds();
void nuke_property_float(const char *lbl, float min, float *val, float max, float step, float dragstep);
#define nuke_prop_float nuke_property_float
void nuke_property_float2(const char *label, float min, float *val, float max, float step, float dragstep);
void nuke_property_float3(const char *label, float min, float *val, float max, float step, float dragstep);
void nuke_input_begin();
void nuke_input_end();
void nuke_input_cursor(int x, int y);
void nuke_input_key(int key, int down);
void nuke_input_button(int btn, int x, int y, int down);
void nuke_input_scroll(float x, float y);
void nuke_input_char(char c);
void nuke_property_int(const char *lbl, int min, int *val, int max, int step);
void nk_radio_button_label(struct nk_context *ctx, const char *label, int *val, int cmp);
void nuke_radio_btn(const char *lbl, int *val, int cmp);
void nuke_checkbox(const char *lbl, int *val);
void nuke_nel_h(int cols, int h);
void nuke_nel(int cols);
void nuke_row(int height);
void nuke_label(const char *s);
void nuke_prop_float(const char *label, float min, float *val, float max, float step, float dragstep);
void nuke_edit_str(char *str);
void nuke_img(char *path);
void nuke_scrolltext(char *str);
int nuke_push_tree_id(const char *name, int id);
void nuke_tree_pop();
int nuke_btn(const char *lbl);
#define nuke_labelf(STR, ...) nk_labelf(ctx, NK_TEXT_LEFT, STR, __VA_ARGS__)
#define nuke_prop_float(LABEL, MIN, VAL, MAX, STEP, DRAG) nk_property_float(ctx, LABEL, MIN, VAL, MAX, STEP, DRAG)
void nuke_labelf(const char *fmt, ...);
#endif

View File

@@ -1,60 +1,43 @@
#include "openglrender.h"
#include "sprite.h"
#include "shader.h"
#include "font.h"
#include "config.h"
#include "static_actor.h"
#include "gameobject.h"
#include "camera.h"
#include "window.h"
#include "debugdraw.h"
#include "log.h"
#include "config.h"
#include "datastream.h"
#include "debugdraw.h"
#include "font.h"
#include "gameobject.h"
#include "log.h"
#include "nuke.h"
#include "shader.h"
#include "sprite.h"
#include "window.h"
#include "model.h"
#include "stb_ds.h"
int renderMode = 0;
#include "HandmadeMath.h"
static GLuint UBO;
static GLuint gridVBO = 0;
static GLuint gridVAO = 0;
static GLuint quadVAO = 0;
static GLuint quadVBO = 0;
static GLuint depthMapFBO = 0;
static GLuint depthMap = 0;
const unsigned int SHADOW_WIDTH = 2048, SHADOW_HEIGHT = 2048;
static struct shader *outlineShader;
static struct shader *modelShader;
static struct shader *shadowShader;
int renderMode = LIT;
struct shader *spriteShader = NULL;
struct shader *wireframeShader = NULL;
struct shader *animSpriteShader = NULL;
static struct shader *textShader;
static struct shader *diffuseShader;
struct sFont *stdFont;
static struct shader *debugDepthQuad;
static struct shader *debugColorPickShader;
static struct shader *debugGridShader;
static struct shader *debugGizmoShader;
struct mStaticActor *gizmo;
float editorFOV = 45.f;
float editorClose = 0.1f;
float editorFar = 1000.f;
mfloat_t editorClearColor[4] = { 0.2f, 0.4f, 0.3f, 1.f };
struct rgba editorClearColor = {35,60,92,255};
float shadowLookahead = 8.5f;
mfloat_t gridSmallColor[3] = { 0.35f, 1.f, 0.9f };
struct rgba gridSmallColor = {
.r = 255 * 0.35f,
.g = 255,
.b = 255 * 0.9f
};
mfloat_t gridBigColor[3] = { 0.92f, 0.92f, 0.68f };
struct rgba gridBigColor = {
.r = 255 * 0.92f,
.g = 255 * 0.92f,
.b = 255 * 0.68f
};
float gridScale = 500.f;
float smallGridUnit = 1.f;
@@ -63,11 +46,6 @@ float gridSmallThickness = 2.f;
float gridBigThickness = 7.f;
float gridOpacity = 0.3f;
mfloat_t proj[16];
float near_plane = -100.f, far_plane = 10.f, plane_size = 60.f;
// Debug render modes
bool renderGizmos = false;
bool showGrid = true;
@@ -82,566 +60,330 @@ bool renderReflection = true;
///// for editing
struct gameobject *selectedobject = NULL;
char objectName[200] = { '\0' }; // object name buffer
char objectName[200] = {'\0'}; // object name buffer
GLuint debugColorPickBO = 0;
GLuint debugColorPickTEX = 0;
sg_image ddimg;
void debug_draw_phys(int draw) {
debugDrawPhysics = draw;
}
struct sprite *tsprite = NULL;
void opengl_rendermode(enum RenderMode r) {
renderMode = r;
}
sg_pipeline mainpip;
sg_pass_action pass_action = {0};
static unsigned int projUBO;
static struct {
sg_pass_action pass_action;
sg_pass pass;
sg_pipeline pipe;
sg_shader shader;
} sg_shadow;
void openglInit()
static struct {
sg_shader shader;
sg_pipeline pipe;
sg_bindings bind;
sg_pass pass;
sg_image img;
sg_image depth_img;
} crt_post;
void make_shader(sg_shader_desc *d, sg_shader result, void *data)
{
if (!mainwin) {
YughError("No window to init OpenGL on.", 1);
exit(1);
if (sg_query_shader_state(result) == SG_RESOURCESTATE_FAILED) {
YughWarn("FAILED MAKING A SHADER: %s\n%s\n%s", d->label, d->vs.source, d->fs.source);
}
}
void fail_shader(sg_shader id, void *data)
{
YughWarn("SHADER DID NOT COMPILE");
}
void destroy_shader(sg_shader shd, void *data)
{
YughWarn("DESTROYED SHADER");
}
static sg_trace_hooks hooks = {
.fail_shader = fail_shader,
.make_shader = make_shader,
.destroy_shader = destroy_shader,
};
void openglInit() {
if (!mainwin) {
YughError("No window to init OpenGL on.", 1);
exit(1);
}
sg_trace_hooks hh = sg_install_trace_hooks(&hooks);
font_init(NULL);
debugdraw_init();
sprite_initialize();
nuke_init(mainwin);
model_init();
sg_color c;
rgba2floats(&c, editorClearColor);
pass_action = (sg_pass_action){
.colors[0] = {.action = SG_ACTION_CLEAR, .value = c}
};
crt_post.shader = sg_compile_shader("shaders/postvert.glsl", "shaders/crtfrag.glsl", &(sg_shader_desc){
.fs.images[0] = {
.name = "diffuse_texture",
.image_type = SG_IMAGETYPE_2D,
.sampler_type = SG_SAMPLERTYPE_FLOAT
}
});
////// MAKE SHADERS
spriteShader = MakeShader("spritevert.glsl", "spritefrag.glsl");
animSpriteShader = MakeShader("animspritevert.glsl", "animspritefrag.glsl");
textShader = MakeShader("textvert.glsl", "textfrag.glsl");
shader_use(textShader);
shader_setint(textShader, "text", 0);
font_init(textShader);
sprite_initialize();
debugdraw_init();
//glEnable(GL_STENCIL_TEST);
glClearColor(editorClearColor[0], editorClearColor[1], editorClearColor[2], editorClearColor[3]);
glEnable(GL_CULL_FACE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//glDisable(GL_DEPTH_TEST);
//glLineWidth(1.3f);
//glEnable(GL_TEXTURE_3D);
//glEnable(GL_MULTISAMPLE);
//glLineWidth(2);
glGenBuffers(1, &projUBO);
glBindBuffer(GL_UNIFORM_BUFFER, projUBO);
glBufferData(GL_UNIFORM_BUFFER, 64, NULL, GL_DYNAMIC_DRAW);
glBindBufferRange(GL_UNIFORM_BUFFER, 0, projUBO, 0, sizeof(float) * 16);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
shader_setUBO(spriteShader, "Projection", 0);
shader_setUBO(textShader, "Projection", 0);
shader_setUBO(animSpriteShader, "Projection", 0);
}
static struct mCamera mcamera = {0};
void openglRender(struct window *window)
{
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(0.3f, 0.3f, 0.3f, 1.f);
//////////// 2D projection
mfloat_t projection[16] = { 0.f };
mat4_ortho(projection, mcamera.transform.position[0],
window->width + mcamera.transform.position[0],
mcamera.transform.position[1],
window->height + mcamera.transform.position[1], -1.f, 1.f);
glBindBuffer(GL_UNIFORM_BUFFER, projUBO);
glBufferSubData(GL_UNIFORM_BUFFER, 0, 64, projection);
//shader_setmat4(vid_shader, "projection", projection);
glEnable(GL_DEPTH_TEST);
// Clear color and depth
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
////// TEXT && GUI
script_call_sym(window->gui_cb);
///// Sprites
glDepthFunc(GL_LESS);
shader_use(spriteShader);
sprite_draw_all();
glDepthFunc(GL_ALWAYS);
shader_use(textShader);
shader_setmat4(textShader, "projection", projection);
}
void openglInit3d(struct window *window)
{
/* TODO: IMG init doesn't work in C++
int init =(0x00000001 | 0x00000002);
int initted =IMG_Init(init);
YughLog(0, SDL_LOG_PRIORITY_ERROR, "Init flags: %d\nInitted values: %d ", init, initted);
if ((initted & (IMG_INIT_JPG | IMG_INIT_PNG)) != (IMG_INIT_JPG | IMG_INIT_PNG)) {
YughLog(0, SDL_LOG_PRIORITY_ERROR,
"IMG_Init: Failed to init required jpg and png support! SDL_IMG error: %s",
IMG_GetError());
crt_post.pipe = sg_make_pipeline(&(sg_pipeline_desc){
.shader = crt_post.shader,
.layout = {
.attrs = {
[0].format = SG_VERTEXFORMAT_FLOAT2,
[1].format = SG_VERTEXFORMAT_FLOAT2
}
}
*/
});
crt_post.img = sg_make_image(&(sg_image_desc){
.render_target = true,
.width = 1200,
.height = 720,
});
crt_post.depth_img = sg_make_image(&(sg_image_desc){
.render_target = true,
.width = 1200,
.height = 720,
.pixel_format = SG_PIXELFORMAT_DEPTH_STENCIL
});
////// MAKE SHADERS
outlineShader = MakeShader("outlinevert.glsl", "outline.glsl");
diffuseShader = MakeShader("simplevert.glsl", "albedofrag.glsl");
modelShader = MakeShader("modelvert.glsl", "modelfrag.glsl");
shadowShader = MakeShader("shadowvert.glsl", "shadowfrag.glsl");
crt_post.pass = sg_make_pass(&(sg_pass_desc){
.color_attachments[0].image = crt_post.img,
.depth_stencil_attachment.image = crt_post.depth_img,
});
textShader = MakeShader("textvert.glsl", "textfrag.glsl");
spriteShader = MakeShader("spritevert.glsl", "spritefrag.glsl");
float crt_quad[] = {
-1, 1, 0, 1,
-1, -1, 0, 0,
1, -1, 1, 0,
-1, 1, 0, 1,
1, -1, 1, 0,
1, 1, 1, 1
};
debugDepthQuad = MakeShader("postvert.glsl", "debugdepthfrag.glsl");
debugColorPickShader =
MakeShader("simplevert.glsl", "debugcolorfrag.glsl");
debugGridShader = MakeShader("gridvert.glsl", "gridfrag.glsl");
debugGizmoShader = MakeShader("gizmovert.glsl", "gizmofrag.glsl");
crt_post.bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
.size = sizeof(crt_quad),
.data = crt_quad
});
stdFont = MakeFont("notosans.ttf", 300);
shader_compile_all();
mat4_perspective_fov(proj, editorFOV * DEG2RADS, window->width,
window->height, editorClose, editorFar);
glEnable(GL_STENCIL_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_TEXTURE_3D);
glEnable(GL_MULTISAMPLE);
glLineWidth(2);
////
// Shadow mapping buffers
////
glGenFramebuffers(1, &depthMapFBO);
glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO);
glGenTextures(1, &depthMap);
glBindTexture(GL_TEXTURE_2D, depthMap);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, SHADOW_WIDTH,
SHADOW_HEIGHT, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
float borderColor[] = { 1.0f, 1.0f, 1.0f, 1.0f };
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
GL_TEXTURE_2D, depthMap, 0);
glDrawBuffer(GL_NONE);
//glReadBuffer(GL_NONE);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
//// Universal buffer to hold projection and light coordinates
glGenBuffers(1, &UBO);
glBindBuffer(GL_UNIFORM_BUFFER, UBO);
glBufferData(GL_UNIFORM_BUFFER, 2 * sizeof(proj), NULL,
GL_STATIC_DRAW);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
glBindBufferRange(GL_UNIFORM_BUFFER, 0, UBO, 0, 2 * sizeof(proj));
glBindBuffer(GL_UNIFORM_BUFFER, UBO);
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(proj), proj);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
////// debug color pick buffer
glGenFramebuffers(1, &debugColorPickBO);
glBindFramebuffer(GL_FRAMEBUFFER, debugColorPickBO);
glGenTextures(1, &debugColorPickTEX);
glBindTexture(GL_TEXTURE_2D, debugColorPickTEX);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, SCREEN_WIDTH, SCREEN_HEIGHT, 0,
GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, debugColorPickTEX, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
//////// Create grid
float gridVertices[] = {
-1.f, 0.f, 1.f, 0.f, 1.f,
-1.f, 0.f, -1.f, 0.f, 0.f,
1.f, 0.f, 1.f, 1.f, 1.f,
1.f, 0.f, -1.f, 1.f, 0.f,
};
glGenVertexArrays(1, &gridVAO);
glGenBuffers(1, &gridVBO);
glBindVertexArray(gridVAO);
glBindBuffer(GL_ARRAY_BUFFER, gridVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(gridVertices), &gridVertices,
GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float),
(void *) 0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float),
(void *) (3 * sizeof(float)));
//////// Create post quad
float quadVertices[] = {
// positions // texture Coords
-1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
};
// setup plane VAO
glGenVertexArrays(1, &quadVAO);
glGenBuffers(1, &quadVBO);
glBindVertexArray(quadVAO);
glBindBuffer(GL_ARRAY_BUFFER, quadVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), &quadVertices,
GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float),
(void *) 0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float),
(void *) (3 * sizeof(float)));
//////
// skybox = new Skybox("skybox");
BindUniformBlock(modelShader->id, "Matrices", 0);
BindUniformBlock(outlineShader->id, "Matrices", 0);
// BindUniformBlock(skybox->shader->id, "Matrices", 0);
BindUniformBlock(diffuseShader->id, "Matrices", 0);
BindUniformBlock(debugGridShader->id, "Matrices", 0);
BindUniformBlock(debugGizmoShader->id, "Matrices", 0);
shader_use(debugDepthQuad);
shader_setint(debugDepthQuad, "depthMap", 0);
glBindTexture(GL_TEXTURE_2D, 0);
//////////// 2D projection
mfloat_t projection[16] = { 0.f };
mat4_ortho(projection, 0.f, SCREEN_WIDTH, SCREEN_HEIGHT, 1.f, -1.f,
1.f);
shader_setmat4(textShader, "projection", projection);
shader_setmat4(spriteShader, "projection", projection);
shader_setmat4(debugGizmoShader, "proj", projection);
}
void openglRender3d(struct window *window, struct mCamera *mcamera)
{
//////// SET NEW PROJECTION
// TODO: Make this not happen every frame
mat4_perspective_fov(proj, editorFOV * DEG2RADS, window->width,
window->height, editorClose, editorFar);
glBindBuffer(GL_UNIFORM_BUFFER, UBO);
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(proj), proj);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
////////// Render a depthmap from the perspective of the directional light
glViewport(0, 0, SHADOW_WIDTH, SHADOW_HEIGHT);
glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO);
glCullFace(GL_BACK);
glClear(GL_DEPTH_BUFFER_BIT);
// Configure matrices with an orthogonal
mfloat_t lightSpaceMatrix[16] = { 0.f };
crt_post.bind.fs_images[0] = crt_post.img;
/*
if (dLight) {
sg_image_desc shadow_desc = {
.render_target = true,
.width = 1024,
.height = 1024,
.pixel_format = SG_PIXELFORMAT_R32F,
};
sg_image depth_img = sg_make_image(&shadow_desc);
shadow_desc.pixel_format = SG_PIXELFORMAT_DEPTH;
ddimg = sg_make_image(&shadow_desc);
mfloat_t lightProjection[16] = { 0.f };
mat4_ortho(lightProjection, -plane_size, plane_size, -plane_size,
plane_size, near_plane, far_plane);
sg_shadow.pass = sg_make_pass(&(sg_pass_desc){
.color_attachments[0].image = depth_img,
.depth_stencil_attachment.image = ddimg,
});
sg_shadow.pass_action = (sg_pass_action) {
.colors[0] = { .action=SG_ACTION_CLEAR, .value = {1,1,1,1} } };
mfloat_t lookPos[3] = { 0.f };
mfloat_t cam_fwd[3] = { 0.f };
vec3_add(lookPos, mcamera->transform.position,
vec3_multiply_f(lookPos,
trans_forward(cam_fwd,
&mcamera->transform),
shadowLookahead));
lookPos[1] = 0.f;
mfloat_t lightLookPos[3] = { 0.f };
mfloat_t light_fwd[3] = { 0.f };
mat4_look_at(lightView,
vec3_subtract(lightLookPos, lookPos,
trans_forward(light_fwd,
&dLight->light.obj.
transform)), lookPos, UP);
mat4_multiply(lightSpaceMatrix, lightProjection, lightView);
//lightSpaceMatrix = lightProjection * lightView;
if (renderDynamicShadows) {
shader_use(shadowShader);
shader_setmat4(shadowShader, "lightSpaceMatrix",
lightSpaceMatrix);
staticactor_draw_shadowcasters(shadowShader);
}
sg_shadow.shader = sg_compile_shader("shaders/shadowvert.glsl", "shaders/shadowfrag.glsl", &(sg_shader_desc){
.vs.uniform_blocks[0] = {
.size = sizeof(float) * 16 * 2,
.uniforms = {
[0] = {.name = "lightSpaceMatrix", .type = SG_UNIFORMTYPE_MAT4},
[1] = {.name = "model", .type = SG_UNIFORMTYPE_MAT4},
}
}
*/
//////////////////////////
});
// Back to the normal render
window_makecurrent(window);
glCullFace(GL_BACK);
// Render the color thing for debug picking
glBindFramebuffer(GL_FRAMEBUFFER, debugColorPickBO);
glClearColor(editorClearColor[0], editorClearColor[1],
editorClearColor[2], editorClearColor[3]);
glClear(GL_COLOR_BUFFER_BIT);
shader_use(debugColorPickShader);
staticactor_draw_dbg_color_pick(debugColorPickShader);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// Clear color and depth
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |
GL_STENCIL_BUFFER_BIT);
if (renderMode == DIRSHADOWMAP) {
// render Depth map to quad for visual debugging
// ---------------------------------------------
shader_use(debugDepthQuad);
shader_setfloat(debugDepthQuad, "near_plane", near_plane);
shader_setfloat(debugDepthQuad, "far_plane", far_plane);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, depthMap);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glBindVertexArray(quadVAO);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glBindVertexArray(0);
} else if (renderMode == OBJECTPICKER) {
// TODO: This rendering mode
shader_use(debugColorPickShader);
} else {
glClearColor(editorClearColor[0], editorClearColor[1],
editorClearColor[2], editorClearColor[3]);
glDepthMask(GL_TRUE);
mfloat_t view[16] = { 0.f };
getviewmatrix(view, mcamera);
glBindBuffer(GL_UNIFORM_BUFFER, UBO);
glBufferSubData(GL_UNIFORM_BUFFER, sizeof(view), sizeof(view),
view);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
switch (renderMode) {
case LIT:
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
shader_use(modelShader);
/*
if (dLight)
dlight_prepshader(dLight, modelShader);
pointlights_prepshader(modelShader);
spotlights_prepshader(modelShader);
sg_shadow.pipe = sg_make_pipeline(&(sg_pipeline_desc){
.shader = sg_shadow.shader,
.layout = {
.attrs = {
[0].format = SG_VERTEXFORMAT_FLOAT3,
}
},
.depth = {
.compare = SG_COMPAREFUNC_LESS_EQUAL,
.write_enabled = true,
.pixel_format = SG_PIXELFORMAT_DEPTH
},
.colors[0].pixel_format = SG_PIXELFORMAT_R32F,
.index_type = SG_INDEXTYPE_UINT16,
.cull_mode = SG_CULLMODE_BACK,
});
*/
shader_setvec3(modelShader, "viewPos",
mcamera->transform.position);
shader_setmat4(modelShader, "lightSpaceMatrix",
lightSpaceMatrix);
shader_setint(modelShader, "shadowMap", 12);
glActiveTexture(GL_TEXTURE);
glBindTexture(GL_TEXTURE_2D, depthMap);
staticactor_draw_models(modelShader);
break;
case UNLIT:
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
shader_use(diffuseShader);
staticactor_draw_models(diffuseShader);
break;
case WIREFRAME:
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
shader_use(diffuseShader);
staticactor_draw_models(diffuseShader);
break;
}
//// skybox
// draw skybox as last
glDepthFunc(GL_LEQUAL);
// skybox->Draw(mcamera);
glDepthFunc(GL_LESS);
if (debugDrawPhysics) {
// Render physics world
//dynamicsWorld->debugDrawWorld();
}
// Draw outline
if (selectedobject != NULL) {
// Draw the selected object outlined
glClearStencil(0);
glClear(GL_STENCIL_BUFFER_BIT);
glStencilFunc(GL_ALWAYS, 1, 0xFF);
glDepthFunc(GL_ALWAYS);
glDepthMask(false);
glColorMask(false, false, false, false);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
glStencilMask(0xFF);
shader_use(diffuseShader);
setup_model_transform(&selectedobject->transform,
diffuseShader, 1.f);
//selectedobject->draw(diffuseShader);
glStencilFunc(GL_NOTEQUAL, 1, 0xFF);
glDepthMask(true);
glColorMask(true, true, true, true);
glStencilMask(0x00);
shader_use(outlineShader);
setup_model_transform(&selectedobject->transform,
outlineShader, 1.f);
//selectedobject->draw(outlineShader);
}
glDepthFunc(GL_LESS);
glStencilMask(0xFF);
glStencilFunc(GL_ALWAYS, 0, 0xFF);
}
////// TEXT && GUI
// glCullFace(GL_FRONT);
glDepthFunc(GL_ALWAYS);
shader_use(textShader);
shader_setmat4(textShader, "projection", window->projection);
mfloat_t fontpos[2] = { 25.f, 25.f };
mfloat_t fontcolor[3] = { 0.5f, 0.8f, 0.2f };
text_settype(stdFont);
renderText("Sample text", fontpos, 0.4f,
fontcolor, -1.f);
sprite_draw(tsprite);
glDepthFunc(GL_LESS);
////// Render grid
if (showGrid) {
glDisable(GL_CULL_FACE);
shader_use(debugGridShader);
mfloat_t gmodel[16] = { 0.f };
mfloat_t gridscale[3] = { 0.f };
vec3(gridscale, gridScale, gridScale, gridScale);
mat4_multiply_f(gmodel, gmodel, gridScale);
// TODO: Hook into here to make the grid scalable
shader_setmat4(debugGridShader, "model", gmodel);
shader_setvec3(debugGridShader, "smallColor", gridSmallColor);
shader_setvec3(debugGridShader, "bigColor", gridBigColor);
shader_setfloat(debugGridShader, "gridScale", gridScale);
shader_setfloat(debugGridShader, "smallUnit", smallGridUnit);
shader_setfloat(debugGridShader, "bigUnit", bigGridUnit);
shader_setfloat(debugGridShader, "smallThickness",
gridSmallThickness);
shader_setfloat(debugGridShader, "largeThickness",
gridBigThickness);
shader_setfloat(debugGridShader, "opacity", gridOpacity);
glBindVertexArray(gridVAO);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glBindVertexArray(0);
}
///// Render gizmos
// These are things that are overlaid on everything else
// glBindFramebuffer(GL_FRAMEBUFFER, 0); // back to default
// glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
// glClear(GL_COLOR_BUFFER_BIT);
// postShader.use();
// glBindVertexArray(quadVAO);
// glBindTexture(GL_TEXTURE_2D, fboTexture);
// glDrawArrays(GL_TRIANGLES, 0, 6);
}
void BindUniformBlock(GLuint shaderID, const char *bufferName,
GLuint bufferBind)
void render_winsize()
{
glUniformBlockBinding(shaderID,
glGetUniformBlockIndex(shaderID, bufferName),
bufferBind);
sg_destroy_image(crt_post.img);
sg_destroy_image(crt_post.depth_img);
sg_destroy_pass(crt_post.pass);
crt_post.img = sg_make_image(&(sg_image_desc){
.render_target = true,
.width = mainwin->width,
.height = mainwin->height
});
crt_post.depth_img = sg_make_image(&(sg_image_desc){
.render_target = true,
.width = mainwin->width,
.height = mainwin->height,
.pixel_format = SG_PIXELFORMAT_DEPTH_STENCIL
});
crt_post.pass = sg_make_pass(&(sg_pass_desc){
.color_attachments[0].image = crt_post.img,
.depth_stencil_attachment.image = crt_post.depth_img,
});
crt_post.bind.fs_images[0] = crt_post.img;
}
static cpBody *camera = NULL;
void set_cam_body(cpBody *body) {
camera = body;
}
cpVect cam_pos() {
return camera ? cpBodyGetPosition(camera) : cpvzero;
}
static float zoom = 1.f;
float cam_zoom() { return zoom; }
void add_zoom(float val) { zoom = val; }
HMM_Mat4 projection = {0.f};
HMM_Mat4 hudproj = {0.f};
HMM_Vec3 dirl_pos = {4, 100, 20};
void openglRender(struct window *window) {
/*
HMM_Mat4 model = HMM_M4D(1.f);
float scale = 0.08;
model = HMM_MulM4(model, HMM_Scale((HMM_Vec3){scale,scale,scale}));
// Shadow pass
sg_begin_pass(sg_shadow.pass, &sg_shadow.pass_action);
sg_apply_pipeline(sg_shadow.pipe);
HMM_Mat4 light_proj = HMM_Orthographic_RH_ZO(-100.f, 100.f, -100.f, 100.f, 1.f, 100.f);
HMM_Mat4 light_view = HMM_LookAt_RH(dirl_pos, (HMM_Vec3){0,0,0}, (HMM_Vec3){0,1,0});
HMM_Mat4 lsm = HMM_MulM4(light_proj, light_view);
HMM_Mat4 subo[2];
subo[0] = lsm;
subo[1] = model;
sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(subo));
for (int i = 0; i < arrlen(duck->meshes); i++) {
sg_bindings sbind = {0};
sbind.vertex_buffers[0] = duck->meshes[i].bind.vertex_buffers[0];
sbind.index_buffer = duck->meshes[i].bind.index_buffer;
sg_apply_bindings(&sbind);
sg_draw(0,duck->meshes[i].face_count,1);
}
sg_end_pass();
draw_model(duck,model, lsm);
*/
// sg_begin_default_pass(&pass_action, window->width, window->height);
sg_begin_pass(crt_post.pass, &pass_action);
//////////// 2D projection
cpVect pos = cam_pos();
projection = HMM_Orthographic_RH_NO(
pos.x - zoom * window->width / 2,
pos.x + zoom * window->width / 2,
pos.y - zoom * window->height / 2,
pos.y + zoom * window->height / 2, -1.f, 1.f);
hudproj = HMM_Orthographic_RH_NO(0, window->width, 0, window->height, -1.f, 1.f);
sprite_draw_all();
sprite_flush();
call_draw();
//// DEBUG
if (debugDrawPhysics) {
gameobject_draw_debugs();
call_debugs();
}
debug_flush(&projection);
// text_flush(&projection);
////// TEXT && GUI
debug_nextpass();
nuke_start();
call_gui();
debug_flush(&hudproj);
text_flush(&hudproj);
// nuke_start();
call_nk_gui();
nuke_end();
sg_end_pass();
sg_begin_default_pass(&pass_action, window->width, window->height);
sg_apply_pipeline(crt_post.pipe);
sg_apply_bindings(&crt_post.bind);
sg_draw(0,6,1);
sg_end_pass();
sg_commit();
debug_newframe();
}
sg_shader sg_compile_shader(const char *v, const char *f, sg_shader_desc *d)
{
YughInfo("Making shader with %s and %s", v, f);
char *vs = slurp_text(v);
char *fs = slurp_text(f);
d->vs.source = vs;
d->fs.source = fs;
sg_shader ret = sg_make_shader(d);
free(vs);
free(fs);
return ret;
}

View File

@@ -1,7 +1,8 @@
#ifndef OPENGL_RENDER_H
#define OPENGL_RENDER_H
#include "render.h"
#include "sokol/sokol_gfx.h"
#include "HandmadeMath.h"
struct mCamera;
struct window;
@@ -9,31 +10,34 @@ struct window;
extern struct shader *spriteShader;
extern struct shader *animSpriteShader;
extern sg_image ddimg;
extern struct sprite *tsprite;
extern int renderMode;
extern HMM_Vec3 dirl_pos;
extern HMM_Mat4 projection;
extern HMM_Mat4 hudproj;
extern float editorClose;
extern float editorFar;
extern float gridScale;
extern float smallGridUnit;
extern float bigGridUnit;
extern float gridSmallThickness;
extern float gridBigThickness;
extern float gridBigColor[];
extern float gridSmallColor[];
extern struct rgba gridBigColor;
extern struct rgba gridSmallColor;
extern float gridOpacity;
extern float editorFOV;
extern float shadowLookahead;
extern float plane_size;
extern float near_plane;
extern float far_plane;
extern char objectName[];
extern GLuint debugColorPickBO;
extern int debugColorPickBO;
extern struct gameobject *selectedobject;
#include <chipmunk/chipmunk.h>
enum RenderMode {
LIT,
UNLIT,
@@ -44,11 +48,20 @@ enum RenderMode {
void openglInit();
void openglRender(struct window *window);
void opengl_rendermode(enum RenderMode r);
void openglInit3d(struct window *window);
void openglRender3d(struct window *window, struct mCamera *camera);
void BindUniformBlock(GLuint shaderID, const char *bufferName,
GLuint bufferBind);
void render_winsize();
void debug_draw_phys(int draw);
void set_cam_body(cpBody *body);
cpVect cam_pos();
float cam_zoom();
void add_zoom(float val);
sg_shader sg_compile_shader(const char *v, const char *f, sg_shader_desc *d);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -27,8 +27,7 @@
#define parson_parson_h
#ifdef __cplusplus
extern "C"
{
extern "C" {
#endif
#if 0
} /* unconfuse xcode */
@@ -40,32 +39,32 @@ extern "C"
#define PARSON_VERSION_STRING "1.4.0"
#include <stddef.h> /* size_t */
#include <stddef.h> /* size_t */
/* Types and enums */
typedef struct json_object_t JSON_Object;
typedef struct json_array_t JSON_Array;
typedef struct json_value_t JSON_Value;
typedef struct json_array_t JSON_Array;
typedef struct json_value_t JSON_Value;
enum json_value_type {
JSONError = -1,
JSONNull = 1,
JSONString = 2,
JSONNumber = 3,
JSONObject = 4,
JSONArray = 5,
JSONBoolean = 6
JSONError = -1,
JSONNull = 1,
JSONString = 2,
JSONNumber = 3,
JSONObject = 4,
JSONArray = 5,
JSONBoolean = 6
};
typedef int JSON_Value_Type;
enum json_result_t {
JSONSuccess = 0,
JSONFailure = -1
JSONSuccess = 0,
JSONFailure = -1
};
typedef int JSON_Status;
typedef void * (*JSON_Malloc_Function)(size_t);
typedef void (*JSON_Free_Function)(void *);
typedef void *(*JSON_Malloc_Function)(size_t);
typedef void (*JSON_Free_Function)(void *);
/* Call only once, before calling any other function from parson API. If not called, malloc and free
from stdlib will be used for all allocations */
@@ -81,35 +80,35 @@ void json_set_escape_slashes(int escape_slashes);
void json_set_float_serialization_format(const char *format);
/* Parses first JSON value in a file, returns NULL in case of error */
JSON_Value * json_parse_file(const char *filename);
JSON_Value *json_parse_file(const char *filename);
/* Parses first JSON value in a file and ignores comments (/ * * / and //),
returns NULL in case of error */
JSON_Value * json_parse_file_with_comments(const char *filename);
JSON_Value *json_parse_file_with_comments(const char *filename);
/* Parses first JSON value in a string, returns NULL in case of error */
JSON_Value * json_parse_string(const char *string);
JSON_Value *json_parse_string(const char *string);
/* Parses first JSON value in a string and ignores comments (/ * * / and //),
returns NULL in case of error */
JSON_Value * json_parse_string_with_comments(const char *string);
JSON_Value *json_parse_string_with_comments(const char *string);
/* Serialization */
size_t json_serialization_size(const JSON_Value *value); /* returns 0 on fail */
size_t json_serialization_size(const JSON_Value *value); /* returns 0 on fail */
JSON_Status json_serialize_to_buffer(const JSON_Value *value, char *buf, size_t buf_size_in_bytes);
JSON_Status json_serialize_to_file(const JSON_Value *value, const char *filename);
char * json_serialize_to_string(const JSON_Value *value);
char *json_serialize_to_string(const JSON_Value *value);
/* Pretty serialization */
size_t json_serialization_size_pretty(const JSON_Value *value); /* returns 0 on fail */
size_t json_serialization_size_pretty(const JSON_Value *value); /* returns 0 on fail */
JSON_Status json_serialize_to_buffer_pretty(const JSON_Value *value, char *buf, size_t buf_size_in_bytes);
JSON_Status json_serialize_to_file_pretty(const JSON_Value *value, const char *filename);
char * json_serialize_to_string_pretty(const JSON_Value *value);
char *json_serialize_to_string_pretty(const JSON_Value *value);
void json_free_serialized_string(char *string); /* frees string from json_serialize_to_string and json_serialize_to_string_pretty */
void json_free_serialized_string(char *string); /* frees string from json_serialize_to_string and json_serialize_to_string_pretty */
/* Comparing */
int json_value_equals(const JSON_Value *a, const JSON_Value *b);
int json_value_equals(const JSON_Value *a, const JSON_Value *b);
/* Validation
This is *NOT* JSON Schema. It validates json by checking if object have identically
@@ -126,45 +125,45 @@ JSON_Status json_validate(const JSON_Value *schema, const JSON_Value *value);
/*
* JSON Object
*/
JSON_Value * json_object_get_value (const JSON_Object *object, const char *name);
const char * json_object_get_string (const JSON_Object *object, const char *name);
size_t json_object_get_string_len(const JSON_Object *object, const char *name); /* doesn't account for last null character */
JSON_Object * json_object_get_object (const JSON_Object *object, const char *name);
JSON_Array * json_object_get_array (const JSON_Object *object, const char *name);
double json_object_get_number (const JSON_Object *object, const char *name); /* returns 0 on fail */
int json_object_get_boolean(const JSON_Object *object, const char *name); /* returns -1 on fail */
JSON_Value *json_object_get_value(const JSON_Object *object, const char *name);
const char *json_object_get_string(const JSON_Object *object, const char *name);
size_t json_object_get_string_len(const JSON_Object *object, const char *name); /* doesn't account for last null character */
JSON_Object *json_object_get_object(const JSON_Object *object, const char *name);
JSON_Array *json_object_get_array(const JSON_Object *object, const char *name);
double json_object_get_number(const JSON_Object *object, const char *name); /* returns 0 on fail */
int json_object_get_boolean(const JSON_Object *object, const char *name); /* returns -1 on fail */
/* dotget functions enable addressing values with dot notation in nested objects,
just like in structs or c++/java/c# objects (e.g. objectA.objectB.value).
Because valid names in JSON can contain dots, some values may be inaccessible
this way. */
JSON_Value * json_object_dotget_value (const JSON_Object *object, const char *name);
const char * json_object_dotget_string (const JSON_Object *object, const char *name);
size_t json_object_dotget_string_len(const JSON_Object *object, const char *name); /* doesn't account for last null character */
JSON_Object * json_object_dotget_object (const JSON_Object *object, const char *name);
JSON_Array * json_object_dotget_array (const JSON_Object *object, const char *name);
double json_object_dotget_number (const JSON_Object *object, const char *name); /* returns 0 on fail */
int json_object_dotget_boolean(const JSON_Object *object, const char *name); /* returns -1 on fail */
JSON_Value *json_object_dotget_value(const JSON_Object *object, const char *name);
const char *json_object_dotget_string(const JSON_Object *object, const char *name);
size_t json_object_dotget_string_len(const JSON_Object *object, const char *name); /* doesn't account for last null character */
JSON_Object *json_object_dotget_object(const JSON_Object *object, const char *name);
JSON_Array *json_object_dotget_array(const JSON_Object *object, const char *name);
double json_object_dotget_number(const JSON_Object *object, const char *name); /* returns 0 on fail */
int json_object_dotget_boolean(const JSON_Object *object, const char *name); /* returns -1 on fail */
/* Functions to get available names */
size_t json_object_get_count (const JSON_Object *object);
const char * json_object_get_name (const JSON_Object *object, size_t index);
JSON_Value * json_object_get_value_at(const JSON_Object *object, size_t index);
JSON_Value * json_object_get_wrapping_value(const JSON_Object *object);
size_t json_object_get_count(const JSON_Object *object);
const char *json_object_get_name(const JSON_Object *object, size_t index);
JSON_Value *json_object_get_value_at(const JSON_Object *object, size_t index);
JSON_Value *json_object_get_wrapping_value(const JSON_Object *object);
/* Functions to check if object has a value with a specific name. Returned value is 1 if object has
* a value and 0 if it doesn't. dothas functions behave exactly like dotget functions. */
int json_object_has_value (const JSON_Object *object, const char *name);
int json_object_has_value(const JSON_Object *object, const char *name);
int json_object_has_value_of_type(const JSON_Object *object, const char *name, JSON_Value_Type type);
int json_object_dothas_value (const JSON_Object *object, const char *name);
int json_object_dothas_value(const JSON_Object *object, const char *name);
int json_object_dothas_value_of_type(const JSON_Object *object, const char *name, JSON_Value_Type type);
/* Creates new name-value pair or frees and replaces old value with a new one.
* json_object_set_value does not copy passed value so it shouldn't be freed afterwards. */
JSON_Status json_object_set_value(JSON_Object *object, const char *name, JSON_Value *value);
JSON_Status json_object_set_string(JSON_Object *object, const char *name, const char *string);
JSON_Status json_object_set_string_with_len(JSON_Object *object, const char *name, const char *string, size_t len); /* length shouldn't include last null character */
JSON_Status json_object_set_string_with_len(JSON_Object *object, const char *name, const char *string, size_t len); /* length shouldn't include last null character */
JSON_Status json_object_set_number(JSON_Object *object, const char *name, double number);
JSON_Status json_object_set_boolean(JSON_Object *object, const char *name, int boolean);
JSON_Status json_object_set_null(JSON_Object *object, const char *name);
@@ -190,15 +189,15 @@ JSON_Status json_object_clear(JSON_Object *object);
/*
*JSON Array
*/
JSON_Value * json_array_get_value (const JSON_Array *array, size_t index);
const char * json_array_get_string (const JSON_Array *array, size_t index);
size_t json_array_get_string_len(const JSON_Array *array, size_t index); /* doesn't account for last null character */
JSON_Object * json_array_get_object (const JSON_Array *array, size_t index);
JSON_Array * json_array_get_array (const JSON_Array *array, size_t index);
double json_array_get_number (const JSON_Array *array, size_t index); /* returns 0 on fail */
int json_array_get_boolean(const JSON_Array *array, size_t index); /* returns -1 on fail */
size_t json_array_get_count (const JSON_Array *array);
JSON_Value * json_array_get_wrapping_value(const JSON_Array *array);
JSON_Value *json_array_get_value(const JSON_Array *array, size_t index);
const char *json_array_get_string(const JSON_Array *array, size_t index);
size_t json_array_get_string_len(const JSON_Array *array, size_t index); /* doesn't account for last null character */
JSON_Object *json_array_get_object(const JSON_Array *array, size_t index);
JSON_Array *json_array_get_array(const JSON_Array *array, size_t index);
double json_array_get_number(const JSON_Array *array, size_t index); /* returns 0 on fail */
int json_array_get_boolean(const JSON_Array *array, size_t index); /* returns -1 on fail */
size_t json_array_get_count(const JSON_Array *array);
JSON_Value *json_array_get_wrapping_value(const JSON_Array *array);
/* Frees and removes value at given index, does nothing and returns JSONFailure if index doesn't exist.
* Order of values in array may change during execution. */
@@ -208,7 +207,7 @@ JSON_Status json_array_remove(JSON_Array *array, size_t i);
* Does nothing and returns JSONFailure if index doesn't exist.
* json_array_replace_value does not copy passed value so it shouldn't be freed afterwards. */
JSON_Status json_array_replace_value(JSON_Array *array, size_t i, JSON_Value *value);
JSON_Status json_array_replace_string(JSON_Array *array, size_t i, const char* string);
JSON_Status json_array_replace_string(JSON_Array *array, size_t i, const char *string);
JSON_Status json_array_replace_string_with_len(JSON_Array *array, size_t i, const char *string, size_t len); /* length shouldn't include last null character */
JSON_Status json_array_replace_number(JSON_Array *array, size_t i, double number);
JSON_Status json_array_replace_boolean(JSON_Array *array, size_t i, int boolean);
@@ -229,33 +228,33 @@ JSON_Status json_array_append_null(JSON_Array *array);
/*
*JSON Value
*/
JSON_Value * json_value_init_object (void);
JSON_Value * json_value_init_array (void);
JSON_Value * json_value_init_string (const char *string); /* copies passed string */
JSON_Value * json_value_init_string_with_len(const char *string, size_t length); /* copies passed string, length shouldn't include last null character */
JSON_Value * json_value_init_number (double number);
JSON_Value * json_value_init_boolean(int boolean);
JSON_Value * json_value_init_null (void);
JSON_Value * json_value_deep_copy (const JSON_Value *value);
void json_value_free (JSON_Value *value);
JSON_Value *json_value_init_object(void);
JSON_Value *json_value_init_array(void);
JSON_Value *json_value_init_string(const char *string); /* copies passed string */
JSON_Value *json_value_init_string_with_len(const char *string, size_t length); /* copies passed string, length shouldn't include last null character */
JSON_Value *json_value_init_number(double number);
JSON_Value *json_value_init_boolean(int boolean);
JSON_Value *json_value_init_null(void);
JSON_Value *json_value_deep_copy(const JSON_Value *value);
void json_value_free(JSON_Value *value);
JSON_Value_Type json_value_get_type (const JSON_Value *value);
JSON_Object * json_value_get_object (const JSON_Value *value);
JSON_Array * json_value_get_array (const JSON_Value *value);
const char * json_value_get_string (const JSON_Value *value);
size_t json_value_get_string_len(const JSON_Value *value); /* doesn't account for last null character */
double json_value_get_number (const JSON_Value *value);
int json_value_get_boolean(const JSON_Value *value);
JSON_Value * json_value_get_parent (const JSON_Value *value);
JSON_Value_Type json_value_get_type(const JSON_Value *value);
JSON_Object *json_value_get_object(const JSON_Value *value);
JSON_Array *json_value_get_array(const JSON_Value *value);
const char *json_value_get_string(const JSON_Value *value);
size_t json_value_get_string_len(const JSON_Value *value); /* doesn't account for last null character */
double json_value_get_number(const JSON_Value *value);
int json_value_get_boolean(const JSON_Value *value);
JSON_Value *json_value_get_parent(const JSON_Value *value);
/* Same as above, but shorter */
JSON_Value_Type json_type (const JSON_Value *value);
JSON_Object * json_object (const JSON_Value *value);
JSON_Array * json_array (const JSON_Value *value);
const char * json_string (const JSON_Value *value);
size_t json_string_len(const JSON_Value *value); /* doesn't account for last null character */
double json_number (const JSON_Value *value);
int json_boolean(const JSON_Value *value);
JSON_Value_Type json_type(const JSON_Value *value);
JSON_Object *json_object(const JSON_Value *value);
JSON_Array *json_array(const JSON_Value *value);
const char *json_string(const JSON_Value *value);
size_t json_string_len(const JSON_Value *value); /* doesn't account for last null character */
double json_number(const JSON_Value *value);
int json_boolean(const JSON_Value *value);
#ifdef __cplusplus
}

48
source/engine/particle.c Normal file
View File

@@ -0,0 +1,48 @@
#include "particle.h"
#include "stb_ds.h"
struct emitter make_emitter() {
struct emitter e = {0};
return e;
}
struct emitter set_emitter(struct emitter e) {
arrsetlen(e.particles, e.max);
e.first = &e.particles[0];
for (int i = 0; i < arrlen(e.particles) - 1; i++) {
e.particles[i].next = &e.particles[i + 1];
}
return e;
}
void free_emitter(struct emitter e) {
arrfree(e.particles);
}
void start_emitter(struct emitter e) {
}
void pause_emitter(struct emitter e) {
}
void stop_emitter(struct emitter e) {
}
void emitter_step(struct emitter e, double dt) {
for (int i = 0; i < arrlen(e.particles); i++) {
if (e.particles[i].life <= 0)
continue;
e.particles[i].pos = cpvadd(e.particles[i].pos, cpvmult(e.particles[i].v, dt));
e.particles[i].angle += e.particles[i].av * dt;
e.particles[i].life -= dt;
if (e.particles[i].life <= 0) {
e.particles[i].next = e.first;
e.first = &e.particles[i];
}
}
}

36
source/engine/particle.h Normal file
View File

@@ -0,0 +1,36 @@
#ifndef PARTICLE_H
#define PARTICLE_H
#include <chipmunk/chipmunk.h>
struct particle {
cpVect pos;
cpVect v; /* velocity */
double angle;
double av; /* angular velocity */
union {
double life;
struct particle *next;
};
};
struct emitter {
struct particle *particles;
struct particle *first;
int max;
double life;
void (*seeder)(struct particle *p); /* Called to initialize each particle */
};
struct emitter make_emitter();
void free_emitter(struct emitter e);
void start_emitter(struct emitter e);
void pause_emitter(struct emitter e);
void stop_emitter(struct emitter e);
void emitter_step(struct emitter e, double dt);
#endif

View File

@@ -1,76 +0,0 @@
#include "registry.h"
#include "gameobject.h"
#include "2dphysics.h"
#include "editor.h"
#include "sprite.h"
struct component components[MAXNAME] = { 0 };
int ncomponent = 0;
#define REGISTER_COMP(NAME) register_component(#NAME, sizeof(struct NAME), make_NAME, dbgdraw_NAME, NAME_gui, NAME_init,
void registry_init()
{
/*
REGISTER_COMP(sprite);
REGISTER_COMP(2d_circle);
REGISTER_COMP(2d_segment);
REGISTER_COMP(2d_box);
REGISTER_COMP(2d_polygon);
REGISTER_COMP(2d_edge);
*/
register_component("Sprite",
sizeof(struct sprite),
make_sprite,
sprite_delete,
sprite_io,
NULL,
sprite_gui,
sprite_init);
register_component("2D Circle Collider",
sizeof(struct phys2d_circle),
Make2DCircle,
phys2d_circledel,
NULL,
phys2d_dbgdrawcircle,
circle_gui,
phys2d_circleinit);
register_component("2D Segment", sizeof(struct phys2d_segment), phys2d_segdel, NULL, Make2DSegment, phys2d_dbgdrawseg, segment_gui, phys2d_seginit);
register_component("2D Box", sizeof(struct phys2d_box), Make2DBox, phys2d_boxdel, NULL, phys2d_dbgdrawbox, box_gui, phys2d_boxinit);
register_component("2D Polygon", sizeof(struct phys2d_poly), Make2DPoly, phys2d_polydel, NULL, phys2d_dbgdrawpoly, poly_gui,phys2d_polyinit);
register_component("2D Edge", sizeof(struct phys2d_edge), Make2DEdge, phys2d_edgedel, NULL, phys2d_dbgdrawedge, edge_gui, phys2d_edgeinit);
}
void register_component(const char *name, size_t size,
void (*make)(struct gameobject * go, struct component * c),
void (*delete)(void *data),
void (*io)(void *data, FILE *f, int read),
void(*draw_debug)(void *data),
void(*draw_gui)(void *data),
void(*init)(void *data, struct gameobject * go))
{
struct component *c = &components[ncomponent++];
c->name = name;
c->make = make;
c->io = io;
c->draw_debug = draw_debug;
c->draw_gui = draw_gui;
c->init = init;
c->data = NULL;
c->delete = delete;
c->id = ncomponent - 1;
c->datasize = size;
}
void comp_draw_debug(struct component *c) {
c->draw_debug(c->data);
}
void comp_draw_gui(struct component *c) {
c->draw_gui(c->data);
}

View File

@@ -1,42 +0,0 @@
#ifndef REGISTRY_H
#define REGISTRY_H
#include <stddef.h>
#include <stdio.h>
#include "config.h"
struct gameobject;
struct component {
const char *name;
void *(*make)(struct gameobject * go); /* Called to create the component */
void (*io)(void *data, FILE *f, int read); /* Pulls data from a component file into the component */
void *data;
struct gameobject *go;
void (*draw_debug)(void *data); /* Draw debugging info in editor */
void (*draw_gui)(void *data); /* Use to draw GUI for editing the component in editor */
void (*delete)(void *data); /* Deletes and cleans up component */
int id;
int datasize;
void (*init)(void *data, struct gameobject * go); /* Inits the component */
};
extern struct component components[MAXNAME];
extern int ncomponent;
void comp_draw_debug(struct component *c);
void comp_draw_gui(struct component *c);
void comp_update(struct component *c, struct gameobject *go);
void registry_init();
void register_component(const char *name, size_t size,
void (*make)(struct gameobject * go, struct component * c),
void (*delete)(void *data),
void (*io)(void *data, FILE *f, int read),
void(*draw_debug)(void *data),
void(*draw_gui)(void *data),
void(*init)(void *data, struct gameobject * go));
#endif

View File

@@ -2,7 +2,62 @@
#define RENDER_H
#define GLFW_INCLUDE_NONE
#include <glad/gl.h>
#include <GLFW/glfw3.h>
#include "sokol/sokol_gfx.h"
#include "HandmadeMath.h"
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;
};
struct boundingbox {
float t;
float b;
float r;
float l;
};
static struct boundingbox cwh2bb(HMM_Vec2 c, HMM_Vec2 wh) {
struct boundingbox bb = {
.t = c.Y + wh.Y/2,
.b = c.Y - wh.Y/2,
.r = c.X + wh.X/2,
.l = c.X - wh.X/2
};
return bb;
}
static float *rgba2floats(float *r, struct rgba c)
{
r[0] = c.r / 255.0;
r[1] = c.g / 255.0;
r[2] = c.b / 255.0;
r[3] = c.a / 255.0;
return r;
}
static sg_blend_state blend_trans = {
.enabled = true,
.src_factor_rgb = SG_BLENDFACTOR_SRC_ALPHA,
.dst_factor_rgb = SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA,
.src_factor_alpha = SG_BLENDFACTOR_SRC_ALPHA,
.src_factor_alpha = SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA
};
#endif

View File

@@ -1,20 +1,22 @@
#include "resources.h"
#include "config.h"
#include <dirent.h>
#include <stddef.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "vec.h"
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include "log.h"
#include "vec.h"
#include <dirent.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <ftw.h>
#include "stb_ds.h"
char *DATA_PATH = NULL;
char *PREF_PATH = NULL;
@@ -29,112 +31,101 @@ static const char *cur_ext = NULL;
struct dirent *c_dirent = NULL;
struct vec *c_vec = NULL;
char pathbuf[MAXPATH];
char pathbuf[MAXPATH + 1];
void resources_init() {
prefabs = vec_make(MAXNAME, 25);
void resources_init()
{
prefabs = vec_make(MAXNAME, 25);
DATA_PATH = malloc(MAXPATH);
getcwd(DATA_PATH, MAXPATH);
strncat(DATA_PATH, "/", MAXPATH);
DATA_PATH = malloc(MAXPATH);
getcwd(DATA_PATH, MAXPATH);
strncat(DATA_PATH, "/", MAXPATH);
if (!PREF_PATH)
PREF_PATH = strdup("./tmp/");
if (!PREF_PATH)
PREF_PATH = strdup("./tmp/");
}
char *get_filename_from_path(char *path, int extension)
{
char *dirpos = strrchr(path, '/');
if (!dirpos)
dirpos = path;
char *get_filename_from_path(char *path, int extension) {
char *dirpos = strrchr(path, '/');
if (!dirpos)
dirpos = path;
char *end = strrchr(path, '\0');
char *end = strrchr(path, '\0');
int offset = 0;
if (!extension) {
char *ext = strrchr(path, '.');
offset = end - ext;
YughInfo("Making %s without extension ...");
}
int offset = 0;
if (!extension) {
char *ext = strrchr(path, '.');
offset = end - ext;
YughInfo("Making %s without extension ...");
}
char *filename = malloc(sizeof(char) * (end - dirpos - offset + 1));
strncpy(filename, dirpos, end - dirpos - offset);
return filename;
char *filename = malloc(sizeof(char) * (end - dirpos - offset + 1));
strncpy(filename, dirpos, end - dirpos - offset);
return filename;
}
char *get_directory_from_path(char *path)
{
const char *dirpos = strrchr(path, '/');
char *directory = (char *) malloc(sizeof(char) * (dirpos - path + 1));
strncpy(directory, path, dirpos - path);
return directory;
char *get_directory_from_path(char *path) {
const char *dirpos = strrchr(path, '/');
char *directory = (char *)malloc(sizeof(char) * (dirpos - path + 1));
strncpy(directory, path, dirpos - path);
return directory;
}
FILE *res_open(char *path, const char *tag)
{
strncpy(pathbuf, DATA_PATH, MAXPATH);
strncat(pathbuf, path, MAXPATH);
FILE *f = fopen(pathbuf, tag);
return f;
FILE *res_open(char *path, const char *tag) {
strncpy(pathbuf, DATA_PATH, MAXPATH);
strncat(pathbuf, path, MAXPATH);
FILE *f = fopen(pathbuf, tag);
return f;
}
static int ext_check(const char *path, const struct stat *sb, int typeflag)
{
if (typeflag == FTW_F) {
const char *ext = strrchr(path, '.');
if (ext != NULL && !strcmp(ext, cur_ext))
vec_add(c_vec, path);
}
static int ext_check(const char *path, const struct stat *sb, int typeflag) {
if (typeflag == FTW_F) {
const char *ext = strrchr(path, '.');
if (ext != NULL && !strcmp(ext, cur_ext))
vec_add(c_vec, path);
}
return 0;
return 0;
}
void fill_extensions(struct vec *vec, const char *path, const char *ext)
{
c_vec = vec;
cur_ext = ext;
vec_clear(c_vec);
ftw(".", ext_check, 10);
void fill_extensions(struct vec *vec, const char *path, const char *ext) {
c_vec = vec;
cur_ext = ext;
vec_clear(c_vec);
ftw(".", ext_check, 10);
}
void findPrefabs()
{
fill_extensions(prefabs, DATA_PATH, EXT_PREFAB);
void findPrefabs() {
fill_extensions(prefabs, DATA_PATH, EXT_PREFAB);
}
char *str_replace_ext(const char *s, const char *newext) {
static char ret[256];
static char ret[256];
strncpy(ret, s, 256);
char *ext = strrchr(ret, '.');
strncpy(ext, newext, 10);
strncpy(ret, s, 256);
char *ext = strrchr(ret, '.');
strncpy(ext, newext, 10);
return ret;
return ret;
}
FILE *path_open(const char *tag, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vsprintf(pathbuf, fmt, args);
va_end(args);
FILE *path_open(const char *tag, const char *fmt, ...) {
va_list args;
va_start(args, fmt);
vsprintf(pathbuf, fmt, args);
va_end(args);
FILE *f = fopen(pathbuf, tag);
return f;
FILE *f = fopen(pathbuf, tag);
return f;
}
char *make_path(const char *file)
{
strncpy(pathbuf, DATA_PATH, MAXPATH);
strncat(pathbuf, file, MAXPATH);
return pathbuf;
char *make_path(const char *file) {
strncpy(pathbuf, DATA_PATH, MAXPATH);
strncat(pathbuf, file, MAXPATH);
return pathbuf;
}
char *strdup(const char *s)
{
char *new = malloc(sizeof(char)*(strlen(s)+1));
strcpy(new, s);
return new;
char *strdup(const char *s) {
char *new = malloc(sizeof(char) * (strlen(s) + 1));
strcpy(new, s);
return new;
}

View File

@@ -1,8 +1,6 @@
#ifndef RESOURCES_H
#define RESOURCES_H
#include <stdio.h>
struct vec;

View File

@@ -1,47 +1,249 @@
#include "script.h"
#include "stdio.h"
#include "log.h"
#include "stdio.h"
#include "mrbffi.h"
#include "ffi.h"
#include "font.h"
s7_scheme *s7 = NULL;
#include "ftw.h"
void script_init() {
s7 = s7_init();
ffi_load();
#include "stb_ds.h"
#include "sys/stat.h"
#include "sys/types.h"
#include "time.h"
JSContext *js = NULL;
JSRuntime *rt = NULL;
#ifdef DBG
#define JS_EVAL_FLAGS JS_EVAL_FLAG_STRICT
#else
#define JS_EVAL_FLAGS JS_EVAL_FLAG_STRICT | JS_EVAL_FLAG_STRIP
#endif
static int load_prefab(const char *fpath, const struct stat *sb, int typeflag) {
if (typeflag != FTW_F)
return 0;
if (!strcmp(".prefab", strrchr(fpath, '.')))
script_dofile(fpath);
return 0;
}
void script_run(const char *script) {
s7_eval_c_string(s7, script);
void script_startup() {
rt = JS_NewRuntime();
JS_SetMaxStackSize(rt, 0);
js = JS_NewContext(rt);
ffi_load();
}
JSValue num_cache[100] = {0};
int js_print_exception(JSValue v) {
#ifdef DBG
if (JS_IsException(v)) {
JSValue exception = JS_GetException(js);
/* TODO: Does it need freed if null? */
if (JS_IsNull(exception))
return 0;
JSValue val = JS_GetPropertyStr(js, exception, "stack");
const char *name = JS_ToCString(js, JS_GetPropertyStr(js, exception, "name"));
const char *msg = JS_ToCString(js, JS_GetPropertyStr(js, exception, "message"));
const char *stack = JS_ToCString(js, val);
YughLog(LOG_SCRIPT, LOG_ERROR, "%s :: %s\n%s", name, msg,stack);
JS_FreeCString(js, name);
JS_FreeCString(js, msg);
JS_FreeCString(js, stack);
JS_FreeValue(js,val);
JS_FreeValue(js,exception);
return 1;
}
#endif
return 0;
}
void script_init() {
/* Load all prefabs into memory */
// if (DBG)
// script_dofile("scripts/debug.js");
// else
script_dofile("scripts/engine.js");
for (int i = 0; i < 100; i++)
num_cache[i] = int2js(i);
}
void script_run(const char *script, const char *file) {
JSValue obj = JS_Eval(js, script, strlen(script), file, JS_EVAL_FLAGS);
js_print_exception(obj);
JS_FreeValue(js,obj);
}
void script_evalf(const char *format, ...)
{
char fmtbuf[4096];
va_list args;
va_start(args, format);
vsnprintf(fmtbuf, 4096, format, args);
va_end(args);
YughWarn(fmtbuf);
JSValue obj = JS_Eval(js, fmtbuf, strlen(fmtbuf), "C eval", JS_EVAL_FLAGS);
js_print_exception(obj);
JS_FreeValue(js,obj);
}
void compile_script(const char *file) {
const char *script = slurp_text(file);
JSValue obj = JS_Eval(js, script, strlen(script), file, JS_EVAL_FLAG_COMPILE_ONLY | JS_EVAL_TYPE_GLOBAL | JS_EVAL_FLAGS);
size_t out_len;
uint8_t *out;
out = JS_WriteObject(js, &out_len, obj, JS_WRITE_OBJ_BYTECODE);
FILE *f = fopen("out.jsc", "w");
fwrite(out, sizeof out[0], out_len, f);
fclose(f);
}
struct callee stacktrace_callee;
time_t file_mod_secs(const char *file) {
struct stat attr;
stat(file, &attr);
return attr.st_mtime;
}
void js_stacktrace() {
#ifdef DBG
call_callee(&stacktrace_callee);
#endif
}
void js_dump_stack() {
js_stacktrace();
}
int script_dofile(const char *file) {
s7_load(s7, file);
const char *script = slurp_text(file);
if (!script) {
YughError("Can't find file %s.", file);
return 0;
}
script_run(script,file);
free(script);
return file_mod_secs(file);
}
/* Call the "update" function in the master game script */
void script_update(double dt) {
}
/* Call the "draw" function in master game script */
void script_draw() {
}
/* Call "editor" function in master game script */
void script_editor() {
}
void script_call(const char *f) {
s7_call(s7, s7_name_to_value(s7, f), s7_nil(s7));
}
void script_call_sym(s7_pointer sym)
JSValue script_runfile(const char *file)
{
s7_call(s7, sym, s7_nil(s7));
const char *script = slurp_text(file);
int bufsize = strlen(script)+50;
char scriptbuffer[bufsize];
snprintf(scriptbuffer,bufsize, "(function(){%s})()", script);
JSValue obj = JS_Eval(js, script, strlen(script), file, JS_EVAL_FLAGS);
js_print_exception(obj);
free(script);
return obj;
}
int script_has_sym(s7_pointer sym) {
return 1;
/* env is an object in the scripting environment;
s is the function to call on that object
*/
void script_eval_w_env(const char *s, JSValue env) {
JSValue v = JS_EvalThis(js, env, s, strlen(s), "internal", JS_EVAL_FLAGS);
js_print_exception(v);
JS_FreeValue(js, v);
}
void script_call_sym(JSValue sym) {
struct callee c;
c.fn = sym;
c.obj = JS_GetGlobalObject(js);
call_callee(&c);
}
JSValue js_callee_exec(struct callee *c, int argc, JSValue *argv)
{
JSValue ret = JS_Call(js, c->fn, c->obj, argc, argv);
js_print_exception(ret);
JS_FreeValue(js, ret);
return JS_NULL;
}
void call_callee(struct callee *c) {
js_callee_exec(c, 0, NULL);
}
void callee_dbl(struct callee c, double d) {
JSValue v = num2js(d);
js_callee_exec(&c, 1, &v);
JS_FreeValue(js, v);
}
void callee_int(struct callee c, int i) {
JSValue v = int2js(i);
js_callee_exec(&c, 1, &v);
JS_FreeValue(js, v);
}
void callee_vec2(struct callee c, cpVect vec) {
JSValue v = vec2js(vec);
js_callee_exec(&c, 1, &v);
JS_FreeValue(js, v);
}
void script_callee(struct callee c, int argc, JSValue *argv) {
js_callee_exec(&c, argc, argv);
}
void send_signal(const char *signal, int argc, JSValue *argv)
{
JSValue globalThis = JS_GetGlobalObject(js);
JSValue sig = JS_GetPropertyStr(js, globalThis, "Signal");
JSValue fn = JS_GetPropertyStr(js, sig, "call");
JSValue args[argc+1];
args[0] = str2js(signal);
for (int i = 0; i < argc; i++)
args[1+i] = argv[i];
JS_Call(js, fn, sig, argc+1, args);
}
static struct callee update_callee;
void register_update(struct callee c) {
update_callee = c;
}
void call_updates(double dt) {
callee_dbl(update_callee, dt);
}
static struct callee gui_callee;
void register_gui(struct callee c) { gui_callee = c; }
void call_gui() { js_callee_exec(&gui_callee, 0, NULL); }
static struct callee nk_gui_callee;
void register_nk_gui(struct callee c) { nk_gui_callee = c; }
void call_nk_gui() { js_callee_exec(&nk_gui_callee, 0, NULL); }
static struct callee physupdate_callee;
void register_physics(struct callee c) { physupdate_callee = c; }
void call_physics(double dt) { callee_dbl(physupdate_callee, dt); }
struct callee debug_callee;
void register_debug(struct callee c) { debug_callee = c; }
void call_debugs() { call_callee(&debug_callee); }
static struct callee draw_callee;
void register_draw(struct callee c) { draw_callee = c; }
void call_draw() { call_callee(&draw_callee); }

View File

@@ -1,17 +1,62 @@
#ifndef SCRIPT_H
#define SCRIPT_H
#include "s7.h"
extern s7_scheme *s7;
#include "quickjs/quickjs.h"
#include <chipmunk/chipmunk.h>
#include <time.h>
extern JSContext *js;
struct callee {
JSValue fn;
JSValue obj;
};
extern struct callee stacktrace_callee;
extern JSValue num_cache[100];
void js_stacktrace();
void script_startup();
void script_init();
void script_run(const char *script);
void script_run(const char *script, const char *file);
void script_evalf(const char *format, ...);
int script_dofile(const char *file);
JSValue script_runfile(const char *file);
void script_update(double dt);
void script_draw();
void duk_run_err();
void js_dump_stack();
void script_editor();
void script_call(const char *f);
void script_call_sym(s7_pointer sym);
int script_has_sym(s7_pointer sym);
void script_call_sym(JSValue sym);
void call_callee(struct callee *c);
void script_callee(struct callee c, int argc, JSValue *argv);
int script_has_sym(void *sym);
void script_eval_w_env(const char *s, JSValue env);
time_t file_mod_secs(const char *file);
void register_update(struct callee c);
void call_updates(double dt);
void call_debugs();
void unregister_gui(struct callee c);
void register_gui(struct callee c);
void register_debug(struct callee c);
void register_nk_gui(struct callee c);
void call_gui();
void call_nk_gui();
void unregister_obj(JSValue obj);
void send_signal(const char *signal, int argc, JSValue *argv);
void register_physics(struct callee c);
void call_physics(double dt);
void register_draw(struct callee c);
void call_draw();
void compile_script(const char *file);
#endif

View File

@@ -1,166 +1,124 @@
#include "shader.h"
#include "render.h"
#include "config.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "font.h"
#include "log.h"
#include "render.h"
#include "resources.h"
#include "stb_ds.h"
#include "timer.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "time.h"
#define SHADER_BUF 10000
static struct shader *shaders;
struct shader *MakeShader(const char *vertpath, const char *fragpath)
{
if (arrcap(shaders) == 0)
arrsetcap(shaders, 20);
struct shader *MakeShader(const char *vertpath, const char *fragpath) {
if (arrcap(shaders) == 0)
arrsetcap(shaders, 20);
struct shader init = {
.vertpath = vertpath,
.fragpath = fragpath };
shader_compile(&init);
arrput(shaders, init);
return &arrlast(shaders);
struct shader init = {
.vertpath = vertpath,
.fragpath = fragpath};
shader_compile(&init);
arrput(shaders, init);
return &arrlast(shaders);
}
int shader_compile_error(GLuint shader)
{
GLint success = 0;
GLchar infoLog[ERROR_BUFFER] = { '\0' };
int shader_compile_error(int shader) {
/*
GLint success = 0;
GLchar infoLog[ERROR_BUFFER] = { '\0' };
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (success) return 0;
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (success) return 0;
glGetShaderInfoLog(shader, ERROR_BUFFER, NULL, infoLog);
YughLog(0, LOG_ERROR, "Shader compilation error.\nLog: %s", infoLog);
glGetShaderInfoLog(shader, ERROR_BUFFER, NULL, infoLog);
YughLog(0, LOG_ERROR, "Shader compilation error.\nLog: %s", infoLog);
return 1;
return 1;
*/
}
int shader_link_error(GLuint shader)
{
GLint success = 0;
GLchar infoLog[ERROR_BUFFER] = { '\0' };
int shader_link_error(int shader) {
/*
GLint success = 0;
GLchar infoLog[ERROR_BUFFER] = { '\0' };
glGetProgramiv(shader, GL_LINK_STATUS, &success);
if (success) return 0;
glGetProgramiv(shader, GL_LINK_STATUS, &success);
if (success) return 0;
glGetProgramInfoLog(shader, ERROR_BUFFER, NULL, infoLog);
YughLog(0, LOG_ERROR, "Shader link error.\nLog: %s", infoLog);
glGetProgramInfoLog(shader, ERROR_BUFFER, NULL, infoLog);
YughLog(0, LOG_ERROR, "Shader link error.\nLog: %s", infoLog);
return 1;
return 1;
*/
}
GLuint load_shader_from_file(const char *path, int type)
{
char spath[MAXPATH] = {'\0'};
int load_shader_from_file(const char *path, int type) {
char spath[MAXPATH] = {'\0'};
sprintf(spath, "%s%s", "shaders/", path);
FILE *f = fopen(make_path(spath), "r'");
if (!path)
perror(spath), exit(1);
sprintf(spath, "%s%s", "shaders/", path);
FILE *f = fopen(make_path(spath), "r'");
if (!path)
perror(spath), exit(1);
char buf[SHADER_BUF] = {'\0'};
long int fsize;
fseek(f, 0, SEEK_END);
fsize = ftell(f);
rewind(f);
fread(buf, fsize, 1, f);
char *buf;
long int fsize;
fseek(f, 0, SEEK_END);
fsize = ftell(f);
buf = malloc(fsize + 1);
rewind(f);
size_t r = fread(buf, sizeof(char), fsize, f);
buf[r] = '\0';
fclose(f);
fclose(f);
/*
GLuint id = glCreateShader(type);
const char *code = buf;
glShaderSource(id, 1, &code, NULL);
glCompileShader(id);
if (shader_compile_error(id)) {
YughError("Error with shader %s.", path);
return 0;
}
free(buf);
GLuint id = glCreateShader(type);
const char *code = buf;
glShaderSource(id, 1, &code, NULL);
glCompileShader(id);
if (shader_compile_error(id)) {
YughError("Error with shader %s.", path);
return 0;
}
return id;
return id;
*/
}
void shader_compile(struct shader *shader)
{
YughInfo("Making shader with %s and %s.", shader->vertpath, shader->fragpath);
void shader_compile(struct shader *shader) {
YughInfo("Making shader with %s and %s.", shader->vertpath, shader->fragpath);
char spath[MAXPATH];
sprintf(spath, "%s%s", "shaders/", shader->vertpath);
const char *vsrc = slurp_text(spath);
sprintf(spath, "%s%s", "shaders/", shader->fragpath);
const char *fsrc = slurp_text(spath);
GLuint vert = load_shader_from_file(shader->vertpath, GL_VERTEX_SHADER);
GLuint frag = load_shader_from_file(shader->fragpath, GL_FRAGMENT_SHADER);
shader->shd = sg_make_shader(&(sg_shader_desc){
.vs.source = vsrc,
.fs.source = fsrc,
.label = shader->vertpath,
});
shader->id = glCreateProgram();
glAttachShader(shader->id, vert);
glAttachShader(shader->id, frag);
glLinkProgram(shader->id);
shader_link_error(shader->id);
glDeleteShader(vert);
glDeleteShader(frag);
free(vsrc);
free(fsrc);
}
void shader_use(struct shader *shader)
{
glUseProgram(shader->id);
void shader_use(struct shader *shader) {
// glUseProgram(shader->id);
}
void shader_setbool(struct shader *shader, const char *name, int val)
{
glUniform1i(glGetUniformLocation(shader->id, name), val);
void shader_compile_all() {
for (int i = 0; i < arrlen(shaders); i++)
shader_compile(&shaders[i]);
}
void shader_setint(struct shader *shader, const char *name, int val)
{
glUniform1i(glGetUniformLocation(shader->id, name), val);
}
void shader_setfloat(struct shader *shader, const char *name, float val)
{
glUniform1f(glGetUniformLocation(shader->id, name), val);
}
void shader_setvec2(struct shader *shader, const char *name, mfloat_t val[2])
{
glUniform2fv(glGetUniformLocation(shader->id, name), 1, val);
}
void shader_setvec3(struct shader *shader, const char *name, mfloat_t val[3])
{
glUniform3fv(glGetUniformLocation(shader->id, name), 1, val);
}
void shader_setvec4(struct shader *shader, const char *name, mfloat_t val[4])
{
glUniform4fv(glGetUniformLocation(shader->id, name), 1, val);
}
void shader_setmat2(struct shader *shader, const char *name, mfloat_t val[4])
{
glUniformMatrix2fv(glGetUniformLocation(shader->id, name), 1, GL_FALSE, val);
}
void shader_setmat3(struct shader *shader, const char *name, mfloat_t val[9])
{
glUniformMatrix3fv(glGetUniformLocation(shader->id, name), 1, GL_FALSE, val);
}
void shader_setmat4(struct shader *shader, const char *name, mfloat_t val[16])
{
glUniformMatrix4fv(glGetUniformLocation(shader->id, name), 1, GL_FALSE, val);
}
void shader_setUBO(struct shader *shader, const char *name, unsigned int index)
{
glUniformBlockBinding(shader->id, glGetUniformBlockIndex(shader->id, name), index);
}
void shader_compile_all()
{
arrwalk(shaders, shader_compile);
}

View File

@@ -1,30 +1,16 @@
#ifndef SHADER_H
#define SHADER_H
#include "mathc.h"
#include "sokol/sokol_gfx.h"
struct shader {
unsigned int id;
const char *vertpath;
const char *fragpath;
sg_shader shd;
const char *vertpath;
const char *fragpath;
};
void shader_compile_all();
struct shader *MakeShader(const char *vertpath, const char *fragpath);
void shader_compile(struct shader *shader);
void shader_use(struct shader *shader);
void shader_setbool(struct shader *shader, const char *name, int val);
void shader_setint(struct shader *shader, const char *name, int val);
void shader_setfloat(struct shader *shader, const char *name, float val);
void shader_setvec2(struct shader *shader, const char *name, mfloat_t val[2]);
void shader_setvec3(struct shader *shader, const char *name, mfloat_t val[3]);
void shader_setvec4(struct shader *shader, const char *name, mfloat_t val[4]);
void shader_setmat2(struct shader *shader, const char *name, mfloat_t val[4]);
void shader_setmat3(struct shader *shader, const char *name, mfloat_t val[9]);
void shader_setmat4(struct shader *shader, const char *name, mfloat_t val[16]);
void shader_setUBO(struct shader *shader, const char *name, unsigned int index);
#endif

View File

@@ -1,126 +0,0 @@
#include "skybox.h"
#include "shader.h"
#include "camera.h"
#include <string.h>
#include <stdlib.h>
#include "openglrender.h"
static const float skyboxVertices[216] = {
-1.0f, 1.0f, -1.0f,
-1.0f, -1.0f, -1.0f,
1.0f, -1.0f, -1.0f,
1.0f, -1.0f, -1.0f,
1.0f, 1.0f, -1.0f,
-1.0f, 1.0f, -1.0f,
-1.0f, -1.0f, 1.0f,
-1.0f, -1.0f, -1.0f,
-1.0f, 1.0f, -1.0f,
-1.0f, 1.0f, -1.0f,
-1.0f, 1.0f, 1.0f,
-1.0f, -1.0f, 1.0f,
1.0f, -1.0f, -1.0f,
1.0f, -1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
1.0f, 1.0f, -1.0f,
1.0f, -1.0f, -1.0f,
-1.0f, -1.0f, 1.0f,
-1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
1.0f, -1.0f, 1.0f,
-1.0f, -1.0f, 1.0f,
-1.0f, 1.0f, -1.0f,
1.0f, 1.0f, -1.0f,
1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
-1.0f, 1.0f, 1.0f,
-1.0f, 1.0f, -1.0f,
-1.0f, -1.0f, -1.0f,
-1.0f, -1.0f, 1.0f,
1.0f, -1.0f, -1.0f,
1.0f, -1.0f, -1.0f,
-1.0f, -1.0f, 1.0f,
1.0f, -1.0f, 1.0f
};
struct mSkybox *MakeSkybox(const char *cubemap)
{
struct mSkybox *newskybox =
(struct mSkybox *) malloc(sizeof(struct mSkybox));
newskybox->shader = MakeShader("skyvert.glsl", "skyfrag.glsl");
shader_compile(newskybox->shader);
glGenVertexArrays(1, &newskybox->VAO);
glGenBuffers(1, &newskybox->VBO);
glBindVertexArray(newskybox->VAO);
glBindBuffer(GL_ARRAY_BUFFER, newskybox->VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(skyboxVertices), &skyboxVertices,
GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float),
(void *) 0);
shader_use(newskybox->shader);
shader_setint(newskybox->shader, "skybox", 0);
/*
const char *faces[6] =
{ "right.jpg", "left.jpg", "top.jpg", "bottom.jpg", "front.jpg",
"back.jpg"
};
*/
glGenTextures(1, &newskybox->id);
glBindTexture(GL_TEXTURE_CUBE_MAP, newskybox->id);
/*char buf[100] = { '\0' };*/
for (int i = 0; i < 6; i++) {
/*
buf[0] = '\0';
strcat(buf, cubemap);
strcat(buf, "/");
strcat(buf, faces[i]);
IMG_Load(buf);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, 2048,
2048, 0, GL_RGB, GL_UNSIGNED_BYTE, data->pixels);
*/
}
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S,
GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T,
GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R,
GL_CLAMP_TO_EDGE);
return newskybox;
}
void skybox_draw(const struct mSkybox *skybox,
const struct mCamera *camera)
{
shader_use(skybox->shader);
mfloat_t view[16] = { 0.f };
getviewmatrix(view, camera);
shader_setmat4(skybox->shader, "skyview", view);
// skybox cube
glBindVertexArray(skybox->VAO);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_CUBE_MAP, skybox->id);
glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArray(0);
}

View File

@@ -1,26 +1,22 @@
#include "sound.h"
#include "resources.h"
#include <stdlib.h>
#include "log.h"
#include "string.h"
#include "math.h"
#include "limits.h"
#include "time.h"
#include "log.h"
#include "math.h"
#include "music.h"
#include "resources.h"
#include "stb_vorbis.h"
#include "string.h"
#include "time.h"
#include <stdlib.h>
#include "samplerate.h"
#include "stb_ds.h"
#include "mix.h"
#include "dsp.h"
#include "mix.h"
#define DR_WAV_IMPLEMENTATION
#include "dr_wav.h"
#define DR_MP3_IMPLEMENTATION
#include "dr_mp3.h"
#include "portaudio.h"
#include "circbuf.h"
#include "miniaudio.h"
#define TSF_IMPLEMENTATION
#include "tsf.h"
@@ -28,305 +24,287 @@
#define TML_IMPLEMENTATION
#include "tml.h"
const char *audioDriver;
static struct {
char *key;
struct wav *value;
} *wavhash = NULL;
void new_samplerate(short *in, short *out, int n, int ch, int sr_in, int sr_out)
{
/*
SDL_AudioStream *stream = SDL_NewAudioStream(AUDIO_S16, ch, sr_in, AUDIO_S16, ch, sr_out);
SDL_AudioStreamPut(stream, in, n * ch * sizeof(short));
SDL_AudioStreamGet(stream, out, n * ch * sizeof(short));
SDL_FreeAudioStream(stream);
*/
}
static struct wav change_channels(struct wav w, int ch) {
short *data = w.data;
int samples = ch * w.frames;
short *new = malloc(sizeof(short) * samples);
struct wav change_samplerate(struct wav w, int rate)
{
//int samples = sizeof(short) * w.ch * w.frames;
//short *new = malloc(samples);
//new_samplerate(w.data, new,
//SDL_AudioStream *stream = SDL_NewAudioStream(AUDIO_S16, w.ch, w.samplerate, AUDIO_S16, w.ch, rate);
//SDL_AudioStreamPut(stream, w.data, w.frames*w.ch*sizeof(short));
int oldframes = w.frames;
w.frames *= (float)rate/w.samplerate;
int samples = sizeof(short) * w.ch * w.frames;
w.samplerate = rate;
short *new = malloc(samples);
//SDL_AudioStreamGet(stream, new, samples);
free(w.data);
w.data = new;
//SDL_FreeAudioStream(stream);
return w;
}
static int patestCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags, void *userData)
{
short *out = (short*)outputBuffer;
bus_fill_buffers(outputBuffer, framesPerBuffer);
return 0;
}
void check_pa_err(PaError e)
{
if (e != paNoError) {
YughError("PA Error: %s", Pa_GetErrorText(e));
exit(1);
if (ch > w.ch) {
/* Sets all new channels equal to the first one */
for (int i = 0; i < w.frames; i++) {
for (int j = 0; j < ch; j++)
new[i * ch + j] = data[i];
}
} else {
/* Simple method; just use first N channels present in wav */
for (int i = 0; i < w.frames; i++)
for (int j = 0; j < ch; j++)
new[i * ch + j] = data[i * ch + j];
}
free(w.data);
w.data = new;
return w;
}
static PaStream *stream_def;
static struct wav change_samplerate(struct wav w, int rate) {
float ratio = (float)rate / w.samplerate;
int outframes = w.frames * ratio;
SRC_DATA ssrc;
float floatdata[w.frames * w.ch];
src_short_to_float_array(w.data, floatdata, w.frames * w.ch);
float resampled[w.ch * outframes];
void wav_norm_gain(struct wav *w, double lv)
{
short tarmax = db2short(lv);
short max = 0;
short *s = w->data;
for (int i = 0; i < w->frames; i++) {
for (int j = 0; j < w->ch; j++) {
max = (abs(s[i*w->ch + j]) > max) ? abs(s[i*w->ch + j]) : max;
}
ssrc.data_in = floatdata;
ssrc.data_out = resampled;
ssrc.input_frames = w.frames;
ssrc.output_frames = outframes;
ssrc.src_ratio = ratio;
src_simple(&ssrc, SRC_SINC_BEST_QUALITY, w.ch);
short *newdata = malloc(sizeof(short) * outframes * w.ch);
src_float_to_short_array(resampled, newdata, outframes * w.ch);
free(w.data);
w.data = newdata;
w.samplerate = rate;
return w;
}
void wav_norm_gain(struct wav *w, double lv) {
short tarmax = db2short(lv);
short max = 0;
short *s = w->data;
for (int i = 0; i < w->frames; i++) {
for (int j = 0; j < w->ch; j++) {
max = (abs(s[i * w->ch + j]) > max) ? abs(s[i * w->ch + j]) : max;
}
}
float mult = (float)max / tarmax;
float mult = (float)max / tarmax;
for (int i = 0; i < w->frames; i++) {
for (int j = 0; j < w->ch; j++) {
s[i*w->ch + j] *= mult;
}
for (int i = 0; i < w->frames; i++) {
for (int j = 0; j < w->ch; j++) {
s[i * w->ch + j] *= mult;
}
}
}
struct osc sin600;
struct osc sin20;
struct dsp_ammod dspammod;
struct dsp_delay dspdel;
struct wav s600wav;
struct sound s600wavsound;
static ma_engine *engine;
void sound_init()
{
PaError err = Pa_Initialize();
check_pa_err(err);
void sound_init() {
ma_result result;
engine = malloc(sizeof(*engine));
result = ma_engine_init(NULL, engine);
if (result != MA_SUCCESS) {
return;
}
return;
int numDevices = Pa_GetDeviceCount();
const PaDeviceInfo *deviceInfo;
mixer_init();
}
for (int i = 0; i < numDevices; i++) {
deviceInfo = Pa_GetDeviceInfo(i);
struct wav *make_sound(const char *wav) {
int index = shgeti(wavhash, wav);
if (index != -1) return wavhash[index].value;
// printf("Device %i: channels %i, sample rate %f, name %s\n", i, deviceInfo->maxOutputChannels, deviceInfo->defaultSampleRate, deviceInfo->name);
struct wav mwav;
// mwav.data = drwav_open_file_and_read_pcm_frames_s16(wav, &mwav.ch, &mwav.samplerate, &mwav.frames, NULL);
if (mwav.samplerate != SAMPLERATE) {
YughInfo("Changing samplerate of %s from %d to %d.", wav, mwav.samplerate, SAMPLERATE);
// mwav = change_samplerate(mwav, SAMPLERATE);
}
if (mwav.ch != CHANNELS) {
YughInfo("Changing channels of %s from %d to %d.", wav, mwav.ch, CHANNELS);
mwav = change_channels(mwav, CHANNELS);
}
mwav.gain = 1.f;
struct wav *newwav = malloc(sizeof(*newwav));
*newwav = mwav;
if (shlen(wavhash) == 0) sh_new_arena(wavhash);
shput(wavhash, wav, newwav);
return newwav;
}
void free_sound(const char *wav) {
struct wav *w = shget(wavhash, wav);
if (w == NULL) return;
free(w->data);
free(w);
shdel(wavhash, wav);
}
struct soundstream *soundstream_make() {
struct soundstream *new = malloc(sizeof(*new));
// new->buf = circbuf_make(sizeof(short), BUF_FRAMES * CHANNELS * 2);
return new;
}
void mini_sound(char *path) {
ma_engine_play_sound(engine, path, NULL);
}
static ma_sound music_sound;
void mini_music_play(char *path) {
ma_sound_uninit(&music_sound);
int result = ma_sound_init_from_file(engine, path, MA_SOUND_FLAG_NO_SPATIALIZATION, NULL, NULL, &music_sound);
if (result != MA_SUCCESS) {
YughInfo("Could not load music at path: %s", path);
}
YughInfo("Loading %s...", path);
ma_sound_start(&music_sound);
}
void mini_music_pause() {
ma_sound_stop(&music_sound);
}
void mini_music_stop() {
ma_sound_stop(&music_sound);
}
void mini_master(float v) {
ma_engine_set_volume(engine, v);
}
void kill_oneshot(struct sound *s) {
free(s);
}
void play_oneshot(struct wav *wav) {
struct sound *new = malloc(sizeof(*new));
new->data = wav;
new->bus = first_free_bus(dsp_filter(new, sound_fillbuf));
new->playing = 1;
new->loop = 0;
new->frame = 0;
new->endcb = kill_oneshot;
}
struct sound *play_sound(struct wav *wav) {
struct sound *new = calloc(1, sizeof(*new));
new->data = wav;
new->bus = first_free_bus(dsp_filter(new, sound_fillbuf));
new->playing = 1;
return new;
}
int sound_playing(const struct sound *s) {
return s->playing;
}
int sound_paused(const struct sound *s) {
return (!s->playing && s->frame < s->data->frames);
}
void sound_pause(struct sound *s) {
s->playing = 0;
bus_free(s->bus);
}
void sound_resume(struct sound *s) {
s->playing = 1;
s->bus = first_free_bus(dsp_filter(s, sound_fillbuf));
}
void sound_stop(struct sound *s) {
s->playing = 0;
s->frame = 0;
bus_free(s->bus);
}
int sound_finished(const struct sound *s) {
return !s->playing && s->frame == s->data->frames;
}
int sound_stopped(const struct sound *s) {
return !s->playing && s->frame == 0;
}
struct mp3 make_music(const char *mp3) {
// drmp3 new;
// if (!drmp3_init_file(&new, mp3, NULL)) {
// YughError("Could not open mp3 file %s.", mp3);
// }
struct mp3 newmp3 = {};
return newmp3;
}
void close_audio_device(int device) {
}
int open_device(const char *adriver) {
return 0;
}
void sound_fillbuf(struct sound *s, short *buf, int n) {
float gainmult = pct2mult(s->data->gain);
short *in = s->data->data;
for (int i = 0; i < n; i++) {
for (int j = 0; j < CHANNELS; j++)
buf[i * CHANNELS + j] = in[s->frame + j] * gainmult;
s->frame++;
if (s->frame == s->data->frames) {
bus_free(s->bus);
s->bus = NULL;
s->endcb(s);
return;
}
PaStreamParameters outparams;
/*
outparams.channelCount = 2;
outparams.device = 19;
outparams.sampleFormat = paInt16;
outparams.suggestedLatency = Pa_GetDeviceInfo(outparams.device)->defaultLowOutputLatency;
outparams.hostApiSpecificStreamInfo = NULL;
*/
//err = Pa_OpenStream(&stream_def, NULL, &outparams, 48000, 4096, paNoFlag, patestCallback, &data);
err = Pa_OpenDefaultStream(&stream_def, 0, 2, paInt16, SAMPLERATE, BUF_FRAMES, patestCallback, NULL);
check_pa_err(err);
err = Pa_StartStream(stream_def);
check_pa_err(err);
}
}
void audio_open(const char *device)
{
//Mix_OpenAudioDevice(44100, MIX_DEFAULT_FORMAT, 2, 2048, device, 0);
void mp3_fillbuf(struct sound *s, short *buf, int n) {
}
void audio_close()
{
//Mix_CloseAudio();
void soundstream_fillbuf(struct soundstream *s, short *buf, int n) {
int max = 1;//s->buf->write - s->buf->read;
int lim = (max < n * CHANNELS) ? max : n * CHANNELS;
for (int i = 0; i < lim; i++) {
// buf[i] = cbuf_shift(s->buf);
}
}
struct wav make_sound(const char *wav)
{
struct wav mwav;
mwav.data = drwav_open_file_and_read_pcm_frames_s16("sounds/alert.wav", &mwav.ch, &mwav.samplerate, &mwav.frames, NULL);
if (mwav.samplerate != SAMPLERATE) {
mwav = change_samplerate(mwav, 48000);
}
mwav.gain = 1.f;
return mwav;
float short2db(short val) {
return 20 * log10(abs(val) / SHRT_MAX);
}
struct soundstream *soundstream_make()
{
struct soundstream *new = malloc(sizeof(*new));
new->buf = circbuf_make(sizeof(short), BUF_FRAMES*CHANNELS*2);
return new;
short db2short(float db) {
return pow(10, db / 20.f) * SHRT_MAX;
}
struct sound *play_sound(struct wav *wav)
{
struct sound *new = calloc(1, sizeof(*new));
new->data = wav;
new->bus = first_free_bus(dsp_filter(new, sound_fillbuf));
new->playing = 1;
return new;
short short_gain(short val, float db) {
return (short)(pow(10, db / 20.f) * val);
}
int sound_playing(const struct sound *s)
{
return s->playing;
float pct2db(float pct) {
if (pct <= 0) return -72.f;
return 10 * log2(pct);
}
int sound_paused(const struct sound *s)
{
return (!s->playing && s->frame < s->data->frames);
}
void sound_pause(struct sound *s)
{
s->playing = 0;
bus_free(s->bus);
}
void sound_resume(struct sound *s)
{
s->playing = 1;
s->bus = first_free_bus(dsp_filter(s, sound_fillbuf));
}
void sound_stop(struct sound *s)
{
s->playing = 0;
s->frame = 0;
bus_free(s->bus);
}
int sound_finished(const struct sound *s)
{
return !s->playing && s->frame == s->data->frames;
}
int sound_stopped(const struct sound *s)
{
return !s->playing && s->frame == 0;
}
struct music make_music(const char *mp3)
{
drmp3 new;
if (!drmp3_init_file(&new, mp3, NULL)) {
YughError("Could not open mp3 file %s.", mp3);
}
}
void audio_init()
{
//audioDriver = SDL_GetAudioDeviceName(0,0);
}
void close_audio_device(int device)
{
//SDL_CloseAudioDevice(device);
}
int open_device(const char *adriver)
{
/*
SDL_AudioSpec audio_spec;
SDL_memset(&audio_spec, 0, sizeof(audio_spec));
audio_spec.freq = SAMPLERATE;
audio_spec.format = AUDIO_F32;
audio_spec.channels = 2;
audio_spec.samples = BUF_FRAMES;
int dev = (int) SDL_OpenAudioDevice(adriver, 0, &audio_spec, NULL, 0);
SDL_PauseAudioDevice(dev, 0);
return dev;
*/
return 0;
}
void sound_fillbuf(struct sound *s, short *buf, int n)
{
float gainmult = pct2mult(s->data->gain);
short *in = s->data->data;
for (int i = 0; i < n; i++) {
for (int j = 0; j < 2; j++) {
buf[i*2+j] = in[s->frame+j] * gainmult;
}
s->frame++;
if (s->frame == s->data->frames) {
if (s->loop > 0) {
s->loop--;
s->frame = 0;
} else {
bus_free(s->bus);
}
}
}
}
void mp3_fillbuf(struct sound *s, short *buf, int n)
{
}
void soundstream_fillbuf(struct soundstream *s, short *buf, int n)
{
int max = s->buf->write - s->buf->read;
int lim = (max < n*CHANNELS) ? max : n*CHANNELS;
for (int i = 0; i < lim; i++) {
buf[i] = cbuf_shift(&s->buf);
}
}
float short2db(short val)
{
return 20*log10(abs((double)val) / SHRT_MAX);
}
short db2short(float db)
{
return pow(10, db/20.f) * SHRT_MAX;
}
short short_gain(short val, float db)
{
return (short)(pow(10, db/20.f) * val);
}
float pct2db(float pct)
{
if (pct <= 0) return -72.f;
return 10*log2(pct);
}
float pct2mult(float pct)
{
if (pct <= 0) return 0.f;
return pow(10, 0.5*log2(pct));
float pct2mult(float pct) {
if (pct <= 0) return 0.f;
return pow(10, 0.5 * log2(pct));
}

View File

@@ -2,7 +2,6 @@
#define SOUND_H
struct circbuf;
struct SDL_AudioStream;
struct Mix_Chunk {
int i;
@@ -22,48 +21,52 @@ struct soundstream {
struct circbuf *buf;
};
struct soundconvstream {
// SDL_AudioStream *srconv;
void *data;
};
struct soundstream *soundstream_make();
/* A playing sound */
struct sound {
int loop;
int frame;
int loop; /* How many times to loop */
unsigned int frame; /* Pointing to the current frame on the wav */
int playing;
float gain;
struct wav *data;
struct bus *bus;
void (*endcb)(struct sound*);
};
/* Represents a sound file */
struct wav {
unsigned int ch;
unsigned int samplerate;
unsigned int frames;
unsigned long long frames;
float gain; /* In dB */
void *data;
};
struct mp3 {
struct music {
};
extern const char *audioDriver;
void sound_init();
void audio_open(const char *device);
void audio_close();
void sound_fillbuf(struct sound *s, short *buf, int n);
struct wav make_sound(const char *wav);
void mini_sound(char *path);
void mini_master(float v);
void mini_music_play(char *path);
void mini_music_pause();
void mini_music_stop();
struct wav *make_sound(const char *wav);
void free_sound(const char *wav);
void wav_norm_gain(struct wav *w, double lv);
struct sound *play_sound(struct wav *wav);
void play_oneshot(struct wav *wav);
int sound_playing(const struct sound *s);
int sound_paused(const struct sound *s);
@@ -73,12 +76,7 @@ void sound_pause(struct sound *s);
void sound_resume(struct sound *s);
void sound_stop(struct sound *s);
struct music make_music(const char *ogg);
struct mp3 make_mp3(const char *mp3);
const char *get_audio_driver();

View File

@@ -160,6 +160,7 @@ struct dsp_filter dsp_filter(void *data, void (*filter)(void *data, short *out,
struct dsp_filter new;
new.data = data;
new.filter = filter;
new.inputs = 0;
return new;
}
@@ -425,10 +426,10 @@ struct dsp_delay dsp_delay_make(unsigned int ms_delay)
/* Circular buffer size is enough to have the delay */
unsigned int datasize = ms_delay * CHANNELS * (SAMPLERATE / 1000);
new.buf = circbuf_init(sizeof(short), datasize);
new.buf.write = datasize;
// new.buf = circbuf_init(sizeof(short), datasize);
// new.buf.write = datasize;
YughInfo("Buffer size is %u.", new.buf.len);
// YughInfo("Buffer size is %u.", new.buf.len);
return new;
}
@@ -439,8 +440,8 @@ void dsp_delay_filbuf(struct dsp_delay *delay, short *buf, int n)
dsp_run(delay->in, cache, n);
for (int i = 0; i < n*CHANNELS; i++) {
cbuf_push(&delay->buf, cache[i] / 2);
buf[i] = cache[i] + cbuf_shift(&delay->buf);
// cbuf_push(&delay->buf, cache[i] / 2);
// buf[i] = cache[i] + cbuf_shift(&delay->buf);
}
}

View File

@@ -2,11 +2,10 @@
#define DSP_H
#define SAMPLERATE 48000
#define BUF_FRAMES 4096
#define BUF_FRAMES 128 /* At 48k, 128 needed for 240fps consistency */
#define CHANNELS 2
#define MUSIZE 2
#include "circbuf.h"
//#include "circbuf.h"
struct dsp_iir;
@@ -66,7 +65,7 @@ struct dsp_filter make_adsr(unsigned int atk, unsigned int dec, unsigned int sus
struct dsp_delay {
unsigned int ms_delay;
struct circbuf buf;
// struct circbuf buf;
struct dsp_filter in;
};
@@ -153,4 +152,6 @@ void dsp_mono(void *p, short *out, int n);
void dsp_bitcrush(void *p, short *out, int n);
void dsp_run(struct dsp_filter filter, short *out, int n);
#endif

104
source/engine/sound/mix.c Normal file
View File

@@ -0,0 +1,104 @@
#include "mix.h"
#include "stddef.h"
#include "time.h"
#include "sound.h"
#include "dsp.h"
#include <string.h>
#include "log.h"
#include <assert.h>
static struct bus bus[256];
static int first = 0; /* First bus available */
static int first_on = -1; /* First bus to fill buffer with */
short mastermix[BUF_FRAMES*CHANNELS];
static int initted = 0;
static float master_volume = 1.f;
void mix_master_vol(float v) {
if (v < 0.f) v = 0.f;
if (v > 100.f) v = 100.f;
master_volume = v / 100.f;
}
void mixer_init() {
for (int i = 0; i < 256; i++) {
bus[i].next = i+1;
bus[i].on = 0;
bus[i].id = i;
}
bus[255].next = -1;
initted = 1;
}
struct bus *first_free_bus(struct dsp_filter in) {
// assert(initted);
for (int i = 0; i < 255; i++)
if (!bus[i].on) {
bus[i].on = 1;
bus[i].in = in;
return &bus[i];
}
return NULL;
if (first == -1) return NULL;
int ret = first;
first = bus[ret].next;
bus[ret].on = 1;
bus[ret].in = in;
if (first_on != -1) bus[first_on].prev = ret;
bus[ret].next = first_on;
bus[ret].prev = -1;
first_on = ret;
return &bus[ret];
}
void bus_free(struct bus *b)
{
if (!b) return;
b->on = 0;
return;
if (first_on == b->id) first_on = b->next;
if (b->next != -1) bus[b->next].prev = b->prev;
if (b->prev != -1) bus[b->prev].next = b->next;
b->next = first;
first = b->id;
b->on = 0;
}
void bus_fill_buffers(short *master, int n) {
int curbus = first_on;
// if (curbus == -1) return;
memset(master, 0, BUF_FRAMES*CHANNELS*sizeof(short));
for (int i = 0; i < 255; i++) {
if (!bus[i].on) continue;
dsp_run(bus[i].in, bus[i].buf, BUF_FRAMES);
for (int j = 0; j < BUF_FRAMES*CHANNELS; j++)
master[j] += bus[i].buf[j] * master_volume;
}
return;
while (curbus != -1) {
int nextbus = bus[curbus].next; /* Save this in case busses get changed during fill */
dsp_run(bus[curbus].in, bus[curbus].buf, BUF_FRAMES);
for (int i = 0; i < BUF_FRAMES*CHANNELS; i++)
master[i] += bus[curbus].buf[i] * master_volume;
curbus = nextbus;
}
}

View File

@@ -7,22 +7,24 @@ struct sound;
struct bus {
int on;
struct dsp_filter in;
short buf[BUF_FRAMES*CHANNELS];
float gain;
};
struct listener {
float x;
float y;
float z;
int on;
int next; /* Next available bus */
int prev;
int id;
};
extern short mastermix[BUF_FRAMES*CHANNELS];
void mixer_init();
struct bus *first_free_bus(struct dsp_filter in);
void bus_fill_buffers(short *master, int n);
/* Set volume between 0 and 100% */
void mix_master_vol(float v);
void bus_free(struct bus *bus);

View File

@@ -52,7 +52,7 @@ void dsp_midi_fillbuf(struct dsp_midi_song *song, void *out, int n)
tsf_render_short(song->sf, o, TSF_BLOCK, 0);
o += TSF_BLOCK*2;
o += TSF_BLOCK*CHANNELS;
song->time += TSF_BLOCK * (1000.f/SAMPLERATE);
}
@@ -61,6 +61,8 @@ void dsp_midi_fillbuf(struct dsp_midi_song *song, void *out, int n)
dsp_pan(&music_pan, out, n);
}
struct bus *musicbus;
void play_song(const char *midi, const char *sf)
{
gsong.midi = tml_load_filename(midi);
@@ -85,7 +87,7 @@ void play_song(const char *midi, const char *sf)
cursong.data = &gsong;
cursong.filter = dsp_midi_fillbuf;
first_free_bus(cursong);
musicbus = first_free_bus(cursong);
}
@@ -96,7 +98,7 @@ void music_play()
void music_stop()
{
bus_free(musicbus);
}
void music_volume()

View File

@@ -14,6 +14,7 @@ struct dsp_midi_song {
extern float music_pan;
void play_song(const char *midi, const char *sf);
void music_stop();
void dsp_midi_fillbuf(struct dsp_midi_song *song, void *out, int n);
#endif

View File

@@ -1,238 +1,361 @@
#include "sprite.h"
#include "timer.h"
#include "render.h"
#include "openglrender.h"
#include "texture.h"
#include "shader.h"
#include "datastream.h"
#include "font.h"
#include "gameobject.h"
#include <string.h>
#include "stb_ds.h"
#include "log.h"
#include "openglrender.h"
#include "render.h"
#include "shader.h"
#include "stb_ds.h"
#include "texture.h"
#include "timer.h"
#include <string.h>
#include <ctype.h>
#include <limits.h>
struct TextureOptions TEX_SPRITE = { 1, 0, 0 };
struct TextureOptions TEX_SPRITE = {1, 0, 0};
struct sprite *sprites;
static struct sprite *sprites;
static int first = -1;
static uint32_t quadVAO;
static sg_shader shader_sprite;
static sg_pipeline pip_sprite;
static sg_bindings bind_sprite;
struct sprite *make_sprite(struct gameobject *go)
{
if (arrcap(sprites) == 0)
arrsetcap(sprites, 100);
struct sprite_vert {
HMM_Vec2 pos;
HMM_Vec2 uv;
struct rgba color;
};
struct sprite sprite = {
.color = {1.f, 1.f, 1.f},
.size = {1.f, 1.f},
.tex = texture_loadfromfile("ph.png"),
.index = arrlen(sprites) };
sprite_init(&sprite, go);
static int num_spriteverts = 5000;
static sg_shader slice9_shader;
static sg_pipeline slice9_pipe;
static sg_bindings slice9_bind;
static float slice9_points[8] = {
0.0, 0.0,
0.0, 1.0,
1.0, 0.0,
1.0, 1.0
};
struct slice9_vert {
HMM_Vec2 pos;
struct uv_n uv;
unsigned short border[4];
HMM_Vec2 scale;
struct rgba color;
};
int make_sprite(int go) {
struct sprite sprite = {
.color = color_white,
.size = {1.f, 1.f},
.tex = texture_loadfromfile(NULL),
.go = go,
.next = -1,
.layer = 0,
.enabled = 1};
if (first < 0) {
arrput(sprites, sprite);
arrlast(sprites).id = arrlen(sprites) - 1;
return arrlen(sprites) - 1;
} else {
int slot = first;
first = id2sprite(first)->next;
*id2sprite(slot) = sprite;
return &arrlast(sprites);
return slot;
}
}
void sprite_init(struct sprite *sprite, struct gameobject *go)
{
sprite->go = go;
YughInfo("Added sprite address %p to sprite array %p.", sprite, &arrlast(sprites));
void sprite_delete(int id) {
struct sprite *sp = id2sprite(id);
sp->go = -1;
sp->next = first;
first = id;
}
void sprite_io(struct sprite *sprite, FILE *f, int read)
{
char path[100];
if (read) {
//fscanf(f, "%s", &path);
for (int i = 0; i < 100; i++) {
path[i] = fgetc(f);
void sprite_enabled(int id, int e) {
sprites[id].enabled = e;
}
if (path[i] == '\0') break;
}
fread(sprite, sizeof(*sprite), 1, f);
sprite_loadtex(sprite, path);
} else {
fputs(tex_get_path(sprite->tex), f);
fputc('\0', f);
fwrite(sprite, sizeof(*sprite), 1, f);
struct sprite *id2sprite(int id) {
if (id < 0) return NULL;
return &sprites[id];
}
static sprite_count = 0;
void sprite_flush() {
sprite_count = 0;
}
void sprite_io(struct sprite *sprite, FILE *f, int read) {
char path[100];
if (read) {
// fscanf(f, "%s", &path);
for (int i = 0; i < 100; i++) {
path[i] = fgetc(f);
if (path[i] == '\0') break;
}
fread(sprite, sizeof(*sprite), 1, f);
sprite_loadtex(sprite, path, ST_UNIT);
} else {
fputs(tex_get_path(sprite->tex), f);
fputc('\0', f);
fwrite(sprite, sizeof(*sprite), 1, f);
}
}
void sprite_delete(struct sprite *sprite)
{
YughInfo("Attempting to delete sprite, address is %p.", sprite);
YughInfo("Number of sprites is %d.", arrlen(sprites));
for (int i = 0; i < arrlen(sprites); i++) {
YughInfo("Address of try sprite is %p.", &sprites[i]);
if (&sprites[i] == sprite) {
YughInfo("Deleted a sprite.");
arrdel(sprites, i);
return;
}
}
void sprite_draw_all() {
sg_apply_pipeline(pip_sprite);
sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(projection));
static struct sprite **layers[5];
for (int i = 0; i < 5; i++)
arrfree(layers[i]);
for (int i = 0; i < arrlen(sprites); i++)
if (sprites[i].go >= 0 && sprites[i].enabled) arrpush(layers[sprites[i].layer], &sprites[i]);
for (int i = 4; i >= 0; i--)
for (int j = 0; j < arrlen(layers[i]); j++)
sprite_draw(layers[i][j]);
}
void sprite_draw_all()
{
//shader_use(spriteShader);
for (int i = 0; i < arrlen(sprites); i++)
sprite_draw(&sprites[i]);
void sprite_loadtex(struct sprite *sprite, const char *path, struct glrect frame) {
sprite->tex = texture_loadfromfile(path);
sprite_setframe(sprite, &frame);
}
void sprite_loadtex(struct sprite *sprite, const char *path)
{
sprite->tex = texture_loadfromfile(path);
void sprite_settex(struct sprite *sprite, struct Texture *tex) {
sprite->tex = tex;
sprite_setframe(sprite, &ST_UNIT);
}
void sprite_loadanim(struct sprite *sprite, const char *path, struct Anim2D anim)
void sprite_initialize() {
shader_sprite = sg_compile_shader("shaders/spritevert.glsl", "shaders/spritefrag.glsl", &(sg_shader_desc){
.vs.uniform_blocks[0] = {
.size = 64,
.layout = SG_UNIFORMLAYOUT_STD140,
.uniforms = {
[0] = {.name = "proj", .type = SG_UNIFORMTYPE_MAT4},
}},
.fs.images[0] = {
.name = "image",
.image_type = SG_IMAGETYPE_2D,
.sampler_type = SG_SAMPLERTYPE_FLOAT,
},
});
pip_sprite = sg_make_pipeline(&(sg_pipeline_desc){
.shader = shader_sprite,
.layout = {
.attrs = {
[0].format = SG_VERTEXFORMAT_FLOAT2,
[1].format = SG_VERTEXFORMAT_FLOAT2,
[2].format = SG_VERTEXFORMAT_UBYTE4N}},
.primitive_type = SG_PRIMITIVETYPE_TRIANGLE_STRIP,
.label = "sprite pipeline",
/* .depth = {
.write_enabled = true,
.compare = SG_COMPAREFUNC_LESS_EQUAL
}
*/
});
bind_sprite.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
.size = sizeof(struct sprite_vert) * num_spriteverts,
.type = SG_BUFFERTYPE_VERTEXBUFFER,
.usage = SG_USAGE_STREAM,
.label = "sprite vertex buffer",
});
slice9_shader = sg_compile_shader("shaders/slice9_v.glsl", "shaders/slice9_f.glsl", &(sg_shader_desc) {
.vs.uniform_blocks[0] = {
.size = 64,
.layout = SG_UNIFORMLAYOUT_STD140,
.uniforms = { [0] = {.name = "projection", .type = SG_UNIFORMTYPE_MAT4},
}},
.fs.images[0] = {
.name = "image",
.image_type = SG_IMAGETYPE_2D,
.sampler_type = SG_SAMPLERTYPE_FLOAT
},
});
slice9_pipe = sg_make_pipeline(&(sg_pipeline_desc){
.shader = slice9_shader,
.layout = {
.attrs = {
[0].format = SG_VERTEXFORMAT_FLOAT2,
[1].format = SG_VERTEXFORMAT_USHORT4N,
[2].format = SG_VERTEXFORMAT_FLOAT2,
[3].format = SG_VERTEXFORMAT_UBYTE4N
}},
.primitive_type = SG_PRIMITIVETYPE_TRIANGLE_STRIP,
});
slice9_bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
.size = sizeof(struct slice9_vert) * 100,
.type = SG_BUFFERTYPE_VERTEXBUFFER,
.usage = SG_USAGE_STREAM,
});
}
/* offset given in texture offset, so -0.5,-0.5 results in it being centered */
void tex_draw(struct Texture *tex, HMM_Vec2 pos, float angle, HMM_Vec2 size, HMM_Vec2 offset, struct glrect r, struct rgba color, int wrap, HMM_Vec2 wrapoffset, float wrapscale) {
struct sprite_vert verts[4];
HMM_Vec2 sposes[4] = {
{0.0,0.0},
{1.0,0.0},
{0.0,1.0},
{1.0,1.0},
};
HMM_Mat2 rot = HMM_RotateM2(angle);
HMM_Vec2 t_scale = {
tex->width * st_s_w(r) * size.X,
tex->height * st_s_h(r) * size.Y
};
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];
verts[i].color = color;
}
if (!wrap) {
verts[0].uv.X = r.s0;
verts[0].uv.Y = r.t1;
verts[1].uv.X = r.s1;
verts[1].uv.Y = r.t1;
verts[2].uv.X = r.s0;
verts[2].uv.Y = r.t0;
verts[3].uv.X = r.s1;
verts[3].uv.Y = r.t0;
} else {
verts[0].uv = HMM_MulV2((HMM_Vec2){0,0}, size);
verts[1].uv = HMM_MulV2((HMM_Vec2){1,0}, size);
verts[2].uv = HMM_MulV2((HMM_Vec2){0,1}, size);
verts[3].uv = HMM_MulV2((HMM_Vec2){1,1}, size);
for (int i = 0; i < 4; i++)
verts[i].uv = HMM_AddV2(verts[i].uv, wrapoffset);
}
bind_sprite.fs_images[0] = tex->id;
sg_append_buffer(bind_sprite.vertex_buffers[0], SG_RANGE_REF(verts));
sg_apply_bindings(&bind_sprite);
sg_draw(sprite_count * 4, 4, 1);
sprite_count++;
}
void sprite_draw(struct sprite *sprite) {
struct gameobject *go = id2go(sprite->go);
if (sprite->tex) {
cpVect cpos = cpBodyGetPosition(go->body);
HMM_Vec2 pos = {cpos.x, cpos.y};
HMM_Vec2 size = {sprite->size.X * go->scale * go->flipx, sprite->size.Y * go->scale * go->flipy};
tex_draw(sprite->tex, pos, cpBodyGetAngle(go->body), size, sprite->pos, sprite->frame, sprite->color, 0, pos, 0);
}
}
void sprite_setanim(struct sprite *sprite, struct TexAnim *anim, int frame) {
if (!sprite) return;
sprite->tex = anim->tex;
sprite->frame = anim->st_frames[frame];
}
void gui_draw_img(const char *img, HMM_Vec2 pos, HMM_Vec2 scale, float angle, int wrap, HMM_Vec2 wrapoffset, float wrapscale, struct rgba color) {
sg_apply_pipeline(pip_sprite);
sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(hudproj));
struct Texture *tex = texture_loadfromfile(img);
HMM_Vec2 offset = {0.f, 0.f};
tex_draw(tex, pos, angle, scale, offset, tex_get_rect(tex), color, wrap, wrapoffset, wrapscale);
}
void slice9_draw(const char *img, HMM_Vec2 pos, HMM_Vec2 dimensions, struct rgba color)
{
sprite->tex = texture_loadfromfile(path);
sprite->anim = anim;
sprite->anim.timer = timer_make(sprite->anim.ms, &incrementAnimFrame, sprite);
sg_apply_pipeline(slice9_pipe);
sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(hudproj));
struct Texture *tex = texture_loadfromfile(img);
struct glrect r = tex_get_rect(tex);
struct slice9_vert verts[4];
HMM_Vec2 sposes[4] = {
{0.0,0.0},
{1.0,0.0},
{0.0,1.0},
{1.0,1.0},
};
for (int i = 0; i < 4; i++) {
verts[i].pos = HMM_MulV2(sposes[i], dimensions);
//verts[i].uv =z sposes[i];
verts[i].color = color;
}
verts[0].uv.u = r.s0 * USHRT_MAX;
verts[0].uv.v = r.t1 * USHRT_MAX;
verts[1].uv.u = r.s1 * USHRT_MAX;
verts[1].uv.v = r.t1 * USHRT_MAX;
verts[2].uv.u = r.s0 * USHRT_MAX;
verts[2].uv.v = r.t0 * USHRT_MAX;
verts[3].uv.u = r.s1 * USHRT_MAX;
verts[3].uv.v = r.t0 * USHRT_MAX;
bind_sprite.fs_images[0] = tex->id;
sg_append_buffer(bind_sprite.vertex_buffers[0], SG_RANGE_REF(verts));
sg_apply_bindings(&bind_sprite);
sg_draw(sprite_count * 4, 4, 1);
sprite_count++;
}
void sprite_setframe(struct sprite *sprite, struct glrect *frame) {
sprite->frame = *frame;
}
void video_draw(struct datastream *ds, HMM_Vec2 pos, HMM_Vec2 size, float rotate, struct rgba color)
{
// shader_use(vid_shader);
/*
sprite->tex = texture_loadanimfromfile(sprite->tex, path, sprite->anim.frames, sprite->anim.dimensions);
static mfloat_t model[16];
memcpy(model, UNITMAT4, sizeof(UNITMAT4));
mat4_translate_vec2(model, position);
mat4_scale_vec2(model, size);
*/
// shader_setmat4(vid_shader, "model", model);
// shader_setvec3(vid_shader, "spriteColor", color);
/*
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, stream->texture_y);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, stream->texture_cb);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, stream->texture_cr);
// TODO: video bind VAO
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
*/
}
void sprite_settex(struct sprite *sprite, struct Texture *tex)
{
sprite->tex = tex;
}
unsigned int incrementAnimFrame(unsigned int interval, struct sprite *sprite)
{
sprite->anim.frame = (sprite->anim.frame + 1) % sprite->anim.frames;
return interval;
}
// TODO: This should be done once for all sprites
void sprite_initialize()
{
uint32_t VBO;
float vertices[] = {
// pos
0.f, 0.f,
1.0f, 0.0f,
0.f, 1.f,
1.f, 1.f
};
glGenVertexArrays(1, &quadVAO);
glGenBuffers(1, &VBO);
glBindVertexArray(quadVAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), &vertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
void sprite_draw(struct sprite *sprite)
{
if (sprite->tex != NULL) {
//shader_use(spriteShader);
mfloat_t model[16] = { 0.f };
mfloat_t r_model[16] = { 0.f };
mfloat_t s_model[16] = { 0.f };
memcpy(model, UNITMAT4, sizeof(UNITMAT4));
memcpy(r_model, UNITMAT4, sizeof(UNITMAT4));
memcpy(s_model, UNITMAT4, sizeof(UNITMAT4));
mfloat_t t_move[2] = { 0.f };
mfloat_t t_scale[2] = { 0.f };
t_scale[0] = sprite->size[0] * sprite->tex->width * sprite->go->scale;
t_scale[1] = sprite->size[1] * sprite->tex->height * sprite->go->scale;
t_move[0] = sprite->pos[0] * t_scale[0];
t_move[1] = sprite->pos[1] * t_scale[1];
mat4_translate_vec2(model, t_move);
mat4_scale_vec2(model, t_scale);
mat4_rotation_z(r_model, cpBodyGetAngle(sprite->go->body));
mat4_multiply(model, r_model, model);
cpVect pos = cpBodyGetPosition(sprite->go->body);
t_move[0] = pos.x;
t_move[1] = pos.y;
mat4_translate_vec2(model, t_move);
shader_setmat4(spriteShader, "model", model);
shader_setvec3(spriteShader, "spriteColor", sprite->color);
//tex_bind(sprite->tex);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, sprite->tex->id);
glBindVertexArray(quadVAO);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
}
void spriteanim_draw(struct sprite *sprite)
{
shader_use(animSpriteShader);
mfloat_t model[16] = { 0.f };
memcpy(model, UNITMAT4, sizeof(UNITMAT4));
mat4_translate_vec2(model, sprite->pos);
mfloat_t msize[2] =
{ sprite->size[0] * sprite->anim.dimensions[0],
sprite->size[1] * sprite->anim.dimensions[1] };
mat4_scale_vec2(model, msize);
shader_setmat4(animSpriteShader, "model", model);
shader_setvec3(animSpriteShader, "spriteColor", sprite->color);
shader_setfloat(animSpriteShader, "frame", sprite->anim.frame);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D_ARRAY, sprite->tex->id);
glBindVertexArray(quadVAO);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
void video_draw(struct datastream *stream, mfloat_t position[2], mfloat_t size[2], float rotate, mfloat_t color[3])
{
shader_use(vid_shader);
static mfloat_t model[16];
memcpy(model, UNITMAT4, sizeof(UNITMAT4));
mat4_translate_vec2(model, position);
mat4_scale_vec2(model, size);
shader_setmat4(vid_shader, "model", model);
shader_setvec3(vid_shader, "spriteColor", color);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, stream->texture_y);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, stream->texture_cb);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, stream->texture_cr);
// TODO: video bind VAO
glBindVertexArray(quadVAO);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}

View File

@@ -3,47 +3,44 @@
#include <stdio.h>
#include "timer.h"
#include "mathc.h"
#include "texture.h"
#include "HandmadeMath.h"
#include "render.h"
struct datastream;
struct gameobject;
struct Texture;
struct timer;
struct Anim2D {
int frames;
int frame;
int dimensions[2];
struct timer *timer;
int ms;
};
struct sprite {
mfloat_t pos[2];
mfloat_t size[2];
HMM_Vec2 pos;
HMM_Vec2 size;
float rotation;
mfloat_t color[3];
int index;
struct Anim2D anim;
struct gameobject *go;
struct rgba color;
int go;
int id;
struct Texture *tex;
struct glrect frame;
int next;
int enabled;
int layer;
};
struct sprite *make_sprite(struct gameobject *go);
void sprite_delete(struct sprite *sprite);
void sprite_init(struct sprite *sprite, struct gameobject *go);
int make_sprite(int go);
struct sprite *id2sprite(int id);
void sprite_delete(int id);
void sprite_enabled(int id, int e);
void sprite_io(struct sprite *sprite, FILE *f, int read);
void sprite_loadtex(struct sprite *sprite, const char *path);
void sprite_loadanim(struct sprite *sprite, const char *path, struct Anim2D anim);
void sprite_loadtex(struct sprite *sprite, const char *path, struct glrect rect);
void sprite_settex(struct sprite *sprite, struct Texture *tex);
void sprite_setanim(struct sprite *sprite, struct TexAnim *anim, int frame);
void sprite_setframe(struct sprite *sprite, struct glrect *frame);
void sprite_initialize();
void sprite_draw(struct sprite *sprite);
void spriteanim_draw(struct sprite *sprite);
void video_draw(struct datastream *ds, mfloat_t pos[2], mfloat_t size[2], float rotate, mfloat_t color[3]);
void video_draw(struct datastream *ds, HMM_Vec2 pos, HMM_Vec2 size, float rotate, struct rgba color);
void sprite_draw_all();
unsigned int incrementAnimFrame(unsigned int interval, struct sprite *sprite);
void sprite_flush();
void gui_draw_img(const char *img, HMM_Vec2 pos, HMM_Vec2 scale, float angle, int wrap, HMM_Vec2 wrapoffset, float wrapscale, struct rgba color);
#endif

View File

@@ -1,94 +0,0 @@
#include "static_actor.h"
//ADDMAKE(StaticActor);
static struct mStaticActor *models[100];
static int numModels = 0;
static struct mStaticActor *shadow_casters[100];
static int numShadowCasters = 0;
struct mStaticActor *curActor = NULL;
void staticactor_draw_dbg_color_pick(struct shader *s)
{
for (int i = 0; i < numModels; i++) {
shader_setvec3(s, "PickingColor", models[i]->obj.editor.color);
setup_model_transform(&models[i]->obj.transform, s, 1.f);
//models[i]->obj.draw(s);
}
}
void staticactor_draw_models(struct shader *s)
{
for (int i = 0; i < numModels; i++) {
setup_model_transform(&models[i]->obj.transform, s, 1.f);
draw_model(models[i]->model, s);
}
}
void staticactor_draw_shadowcasters(struct shader *s)
{
for (int i = 0; i < numShadowCasters; i++) {
setup_model_transform(&shadow_casters[i]->obj.transform, s, 1.f);
//models[i]->obj.draw(s);
}
}
/*
void StaticActor::serialize(FILE * file)
{
GameObject::serialize(file);
SerializeBool(file, &castShadows);
Serializecstr(file, currentModelPath);
}
void StaticActor::deserialize(FILE * file)
{
GameObject::deserialize(file);
DeserializeBool(file, &castShadows);
Deserializecstr(file, currentModelPath, MAXPATH);
curActor = this;
set_new_model(currentModelPath);
}
*/
struct mStaticActor *MakeStaticActor(const char *modelPath)
{
struct mStaticActor *newsa =
(struct mStaticActor *) malloc(sizeof(struct mStaticActor));
newsa->model = GetExistingModel(modelPath);
models[numModels++] = newsa;
return newsa;
}
/*
Serialize *make_staticactor()
{
StaticActor *nactor = (StaticActor *) malloc(sizeof(StaticActor));
return nactor;
}
*/
#include "nuke.h"
void staticactor_gui(struct mStaticActor *sa)
{
object_gui(&sa->obj);
if (nk_tree_push(ctx, NK_TREE_NODE, "Model", NK_MINIMIZED)) {
nk_checkbox_label(ctx, "Cast Shadows", &sa->castShadows);
nk_labelf(ctx, NK_TEXT_LEFT, "Model path: %s", sa->currentModelPath);
//ImGui::SameLine();
if (nk_button_label(ctx, "Load model")) {
//asset_command = set_new_model;
curActor = sa;
}
}
}

View File

@@ -1,24 +0,0 @@
#ifndef STATIC_ACTOR_H
#define STATIC_ACTOR_H
#include "gameobject.h"
#include "model.h"
#include "shader.h"
struct mStaticActor {
struct gameobject obj;
struct model *model;
char *modelPath;
char currentModelPath[MAXPATH];
bool castShadows;
};
void staticactor_draw_dbg_color_pick(struct shader *s);
void staticactor_draw_models(struct shader *s);
void staticactor_draw_shadowcasters(struct shader *s);
struct mStaticActor *MakeStaticActor();
void staticactor_gui(struct mStaticActor *sa);
extern struct mStaticActor *curActor;
#endif

View File

@@ -1,252 +1,330 @@
#include "texture.h"
#include "render.h"
#include <stdio.h>
#include <stb_image.h>
#include <stb_ds.h>
#include "log.h"
#include <math.h>
#include "render.h"
#include "sokol/sokol_gfx.h"
#include "util.h"
#include <math.h>
#include <stb_ds.h>
#include <stb_image.h>
#define STB_IMAGE_RESIZE_IMPLEMENTATION
#include "stb_image_resize.h"
#include <stdio.h>
struct glrect ST_UNIT = {0.f, 1.f, 0.f, 1.f};
static struct {
char *key;
struct Texture *value;
char *key;
struct Texture *value;
} *texhash = NULL;
struct Texture *tex_default;
struct Texture *texture_pullfromfile(const char *path)
struct Texture *texture_notex() {
return texture_pullfromfile("./icons/no_tex.png");
}
unsigned int next_pow2(unsigned int v)
{
int index = shgeti(texhash, path);
if (index != -1)
return texhash[index].value;
v--;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
v++;
return v;
}
struct Texture *tex = calloc(1, sizeof(*tex));
tex->flipy = 0;
tex->opts.sprite = 1;
tex->opts.gamma = 0;
tex->anim.frames = 1;
tex->anim.ms = 1;
int mip_levels(int width, int height)
{
int levels = 0;
while (width > 1 || height > 1)
{
width >>= 1;
height >>= 1;
levels++;
}
return levels;
}
int n;
stbi_set_flip_vertically_on_load(0);
unsigned char *data = stbi_load(path, &tex->width, &tex->height, &n, 4);
int mip_wh(int w, int h, int *mw, int *mh, int lvl)
{
w >>= lvl;
h >>= lvl;
while (data == NULL) {
YughError("STBI failed to load file %s with message: %s", path, stbi_failure_reason());
return NULL;
}
if (w == 0 && h == 0)
return 1;
tex->data = data;
*mw = w ? w : 1;
*mh = h ? h : 1;
if (shlen(texhash) == 0)
sh_new_arena(texhash);
return 0;
}
shput(texhash, path, tex);
/* If an empty string or null is put for path, loads default texture */
struct Texture *texture_pullfromfile(const char *path) {
if (!path) return texture_notex();
tex->id = 0;
int index = shgeti(texhash, path);
if (index != -1)
return texhash[index].value;
return tex;
YughInfo("Loading texture %s.", path);
struct Texture *tex = calloc(1, sizeof(*tex));
tex->opts.sprite = 1;
tex->opts.mips = 0;
tex->opts.gamma = 0;
tex->opts.wrapx = 1;
tex->opts.wrapy = 1;
int n;
unsigned char *data = stbi_load(path, &tex->width, &tex->height, &n, 4);
if (data == NULL) {
YughError("STBI failed to load file %s with message: %s\nOpening default instead.", path, stbi_failure_reason());
return texture_notex();
}
unsigned int nw = next_pow2(tex->width);
unsigned int nh = next_pow2(tex->height);
tex->data = data;
int filter;
if (tex->opts.sprite) {
filter = SG_FILTER_NEAREST;
} else {
filter = SG_FILTER_LINEAR;
}
sg_image_data sg_img_data;
int mips = mip_levels(tex->width, tex->height)+1;
YughInfo("Has %d mip levels, from wxh %dx%d, pow2 is %ux%u.", mips, tex->width, tex->height,nw,nh);
int mipw, miph;
mipw = tex->width;
miph = tex->height;
sg_img_data.subimage[0][0] = (sg_range){ .ptr = data, .size = mipw*miph*4 };
unsigned char *mipdata[mips];
mipdata[0] = data;
for (int i = 1; i < mips; i++) {
int w, h, mipw, miph;
mip_wh(tex->width, tex->height, &mipw, &miph, i-1); /* mipw miph are previous iteration */
mip_wh(tex->width, tex->height, &w, &h, i);
mipdata[i] = malloc(w * h * 4);
stbir_resize_uint8(mipdata[i-1], mipw, miph, 0, mipdata[i], w, h, 0, 4);
sg_img_data.subimage[0][i] = (sg_range){ .ptr = mipdata[i], .size = w*h*4 };
mipw = w;
miph = h;
}
tex->id = sg_make_image(&(sg_image_desc){
.type = SG_IMAGETYPE_2D,
.width = tex->width,
.height = tex->height,
.usage = SG_USAGE_IMMUTABLE,
.min_filter = SG_FILTER_NEAREST_MIPMAP_NEAREST,
.mag_filter = SG_FILTER_NEAREST,
.num_mipmaps = mips,
.wrap_u = SG_WRAP_REPEAT,
.wrap_v = SG_WRAP_REPEAT,
.data = sg_img_data
});
if (shlen(texhash) == 0)
sh_new_arena(texhash);
shput(texhash, path, tex);
return tex;
}
void texture_sync(const char *path) {
YughWarn("Need to implement texture sync.");
}
char *tex_get_path(struct Texture *tex) {
for (int i = 0; i < shlen(texhash); i++) {
if (tex == texhash[i].value) {
YughInfo("Found key %s", texhash[i].key);
return texhash[i].key;
}
for (int i = 0; i < shlen(texhash); i++) {
if (tex == texhash[i].value) {
YughInfo("Found key %s", texhash[i].key);
return texhash[i].key;
}
}
return NULL;
return "";
}
struct Texture *texture_loadfromfile(const char *path)
{
struct Texture *new = texture_pullfromfile(path);
struct Texture *texture_loadfromfile(const char *path) {
struct Texture *new = texture_pullfromfile(path);
/*
if (new->id == 0) {
glGenTextures(1, &new->id);
if (new == NULL) {
YughError("Texture %s not loaded! Loading the default instead ...", path);
new = texture_pullfromfile("./ph.png");
}
//tex_gpu_load(new);
if (new->id == 0) {
glGenTextures(1, &new->id);
tex_gpu_load(new);
YughInfo("Loaded texture path %s", path);
}
return new;
YughInfo("Loaded texture path %s", path);
}
*/
return new;
}
void tex_gpu_reload(struct Texture *tex) {
tex_gpu_free(tex);
void tex_pull(struct Texture *tex)
{
if (tex->data != NULL)
tex_flush(tex);
int n;
char *path = tex_get_path(tex);
stbi_set_flip_vertically_on_load(0);
tex->data = stbi_load(path, &tex->width, &tex->height, &n, 4);
if (tex->data == NULL)
YughError("STBI failed to load file %s with message: %s", path, stbi_failure_reason());
// tex_gpu_load(tex);
}
void tex_flush(struct Texture *tex)
{
free(tex->data);
void anim_calc(struct anim2d *anim) {
anim->size[0] = anim->anim->tex->width * st_s_w(anim->anim->st_frames[anim->frame]);
anim->size[1] = anim->anim->tex->height * st_s_h(anim->anim->st_frames[anim->frame]);
}
void tex_gpu_reload(struct Texture *tex)
{
tex_gpu_free(tex);
void anim_incr(struct anim2d *anim) {
anim->frame = (anim->frame + 1) % arrlen(anim->anim->st_frames);
tex_gpu_load(tex);
if (!anim->anim->loop && anim->frame == arrlen(anim->anim->st_frames))
anim_pause(anim);
anim_calc(anim);
}
void tex_free(struct Texture *tex)
{
free(tex->data);
//free(tex->path);
free(tex);
void anim_decr(struct anim2d *anim) {
anim->frame = (anim->frame + arrlen(anim->anim->st_frames) - 1) % arrlen(anim->anim->st_frames);
anim_calc(anim);
}
void tex_gpu_load(struct Texture *tex)
{
glBindTexture(GL_TEXTURE_2D, tex->id);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex->width, tex->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, tex->data);
glGenerateMipmap(GL_TEXTURE_2D);
if (tex->opts.sprite) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
} else {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
struct glrect anim_get_rect(struct anim2d *anim) {
return anim->anim->st_frames[anim->frame];
}
void tex_incr_anim(struct TexAnimation *tex_anim)
{
anim_incr(tex_anim);
if (!tex_anim->tex->anim.loop && tex_anim->frame == tex_anim->tex->anim.frames)
anim_pause(tex_anim);
void anim_setframe(struct anim2d *anim, int frame) {
anim->frame = frame;
anim_calc(anim);
}
void anim_incr(struct TexAnimation *anim)
{
anim->frame = (anim->frame + 1) % anim->tex->anim.frames;
tex_anim_calc_uv(anim);
struct TexAnim *anim2d_from_tex(const char *path, int frames, int fps) {
struct TexAnim *anim = malloc(sizeof(*anim));
anim->tex = texture_loadfromfile(path);
texanim_fromframes(anim, frames);
anim->ms = (float)1 / fps;
return anim;
}
void anim_decr(struct TexAnimation *anim)
{
anim->frame = (anim->frame + anim->tex->anim.frames - 1) % anim->tex->anim.frames;
tex_anim_calc_uv(anim);
void texanim_fromframes(struct TexAnim *anim, int frames) {
if (anim->st_frames) {
free(anim->st_frames);
}
arrsetlen(anim->st_frames, frames);
float width = (float)1 / frames;
for (int i = 0; i < frames; i++) {
anim->st_frames[i].s0 = width * i;
anim->st_frames[i].s1 = width * (i + 1);
anim->st_frames[i].t0 = 0.f;
anim->st_frames[i].t1 = 1.f;
}
}
void anim_setframe(struct TexAnimation *anim, int frame)
{
anim->frame = frame;
tex_anim_calc_uv(anim);
void tex_gpu_free(struct Texture *tex) {
/*
if (tex->id != 0) {
glDeleteTextures(1, &tex->id);
tex->id = 0;
}
*/
}
void tex_anim_set(struct TexAnimation *anim)
{
if (anim->playing) {
timer_remove(anim->timer);
anim->timer = timer_make(1.f / anim->tex->anim.ms, tex_incr_anim, anim);
}
tex_anim_calc_uv(anim);
int anim_frames(struct TexAnim *a) {
return arrlen(a->st_frames);
}
void tex_gpu_free(struct Texture *tex)
{
if (tex->id != 0) {
glDeleteTextures(1, &tex->id);
tex->id = 0;
}
struct glrect tex_get_rect(struct Texture *tex) {
return ST_UNIT;
}
void tex_anim_calc_uv(struct TexAnimation *anim)
{
struct Rect uv;
uv.w = 1.f / anim->tex->anim.frames;
uv.h = 1.f;
uv.y = 0.f;
uv.x = uv.w * (anim->frame);
anim->uv = uv;
cpVect tex_get_dimensions(struct Texture *tex) {
if (!tex) return cpvzero;
cpVect d;
d.x = tex->width;
d.y = tex->height;
return d;
}
void tex_bind(struct Texture *tex)
{
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex->id);
glBindTexture(GL_TEXTURE_2D_ARRAY, tex->id);
void tex_bind(struct Texture *tex) {
/* glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex->id);
glBindTexture(GL_TEXTURE_2D_ARRAY, tex->id);
*/
}
void anim_play(struct TexAnimation *anim)
{
if (anim->playing)
return;
/********************** ANIM2D ****************/
if (anim->frame == anim->tex->anim.frames)
anim->frame = 0;
anim->playing = 1;
if (anim->timer == NULL)
anim->timer = timer_make(1.f / anim->tex->anim.ms, tex_incr_anim, anim);
else
timer_settime(anim->timer, 1.f/anim->tex->anim.ms);
timer_start(anim->timer);
void anim_load(struct anim2d *anim, const char *path) {
anim->anim = &texture_pullfromfile(path)->anim;
anim->anim->tex->opts.animation = 1;
anim_stop(anim);
anim_play(anim);
}
void anim_stop(struct TexAnimation *anim)
{
if (!anim->playing)
return;
void anim_play(struct anim2d *anim) {
if (anim->playing)
return;
anim->playing = 0;
if (anim->frame == anim_frames(anim->anim))
anim->frame = 0;
anim->pausetime = 0;
timer_stop(anim->timer);
tex_anim_calc_uv(anim);
anim->playing = 1;
if (anim->timer == NULL)
anim->timer = id2timer(timer_make(1.f / anim->anim->ms, anim_incr, anim, 0));
else
timerr_settime(anim->timer, 1.f / anim->anim->ms);
timer_start(anim->timer);
}
void anim_pause(struct TexAnimation *anim)
{
if (!anim->playing)
return;
void anim_stop(struct anim2d *anim) {
if (!anim->playing)
return;
anim->playing = 0;
timer_pause(anim->timer);
anim->playing = 0;
anim->frame = 0;
anim->pausetime = 0;
timer_stop(anim->timer);
}
void anim_fwd(struct TexAnimation *anim)
{
anim_incr(anim);
void anim_pause(struct anim2d *anim) {
if (!anim->playing)
return;
anim->playing = 0;
timer_pause(anim->timer);
}
void anim_bkwd(struct TexAnimation *anim)
{
anim_decr(anim);
void anim_fwd(struct anim2d *anim) {
anim_incr(anim);
}
void anim_bkwd(struct anim2d *anim) {
anim_decr(anim);
}
float st_s_w(struct glrect st) {
return (st.s1 - st.s0);
}
float st_s_h(struct glrect st) {
return (st.t1 - st.t0);
}

View File

@@ -2,78 +2,107 @@
#define TEXTURE_H
#include "timer.h"
#include <chipmunk/chipmunk.h>
#include "sokol/sokol_gfx.h"
#define TEX_SPEC 0
#define TEX_NORM 1
#define TEX_HEIGHT 2
#define TEX_DIFF 3
struct Rect {
float x;
float y;
float w;
float h;
/* Normalized S,T coordinates for rendering */
struct glrect {
float s0;
float s1;
float t0;
float t1;
};
struct TexAnimation {
float st_s_w(struct glrect st);
float st_s_h(struct glrect st);
extern struct glrect ST_UNIT;
/* Pixel U,V coordiantes */
struct uvrect {
int u0;
int u1;
int v0;
int v1;
};
/* Tracks a playing animation */
/* Objects should keep this, and just change what TexAnim they are pointing to */
struct anim2d {
int frame;
int playing;
int pausetime;
struct timer *timer;
struct Rect uv;
struct Texture *tex;
struct TexAnim *anim;
float size[2]; /* Current size of animation in pixels*/
};
/* Describes an animation on a particular texture */
struct TexAnim {
int frames;
int dimensions[2];
struct Texture *tex;
struct glrect *st_frames; /* Dynamic array of frames of animation */
int ms;
int loop;
};
struct TextureOptions {
int sprite;
int mips;
unsigned int gamma:1;
int animation;
int wrapx;
int wrapy;
};
/* Represents an actual texture on the GPU */
struct Texture {
int type;
unsigned int id;
int width;
int height;
short flipy;
unsigned char *data; // Pixel data of the texture, loaded in at runtime
sg_image id; /* ID reference for the GPU memory location of the texture */
uint16_t width;
uint16_t height;
unsigned char *data;
struct TextureOptions opts;
struct TexAnim anim;
};
struct Image {
struct Texture *tex;
struct glrect frame;
};
struct Texture *texture_pullfromfile(const char *path); // Create texture from image
struct Texture *texture_loadfromfile(const char *path); // Create texture & load to gpu
void tex_gpu_load(struct Texture *tex); // Send texture data to gpu
void texture_sync(const char *path);
struct Texture *str2tex(const char *path);
void tex_gpu_reload(struct Texture *tex); // gpu_free then gpu_load
void tex_gpu_free(struct Texture *tex); // Remove texture data from gpu
void tex_free(struct Texture *tex); // Delete struct
void tex_flush(struct Texture *tex); // Remove pixel data from struct
void tex_pull(struct Texture *tex); // Pull pixel data from image
void tex_bind(struct Texture *tex); // Bind to gl context
char * tex_get_path(struct Texture *tex); // Get image path for texture
void anim_play(struct TexAnimation *anim);
void anim_setframe(struct TexAnimation *anim, int frame);
void anim_stop(struct TexAnimation *anim);
void anim_pause(struct TexAnimation *anim);
void anim_fwd(struct TexAnimation *anim);
void anim_bkwd(struct TexAnimation *anim);
void anim_incr(struct TexAnimation *anim);
void anim_decr(struct TexAnimation *anim);
struct TexAnim *anim2d_from_tex(const char *path, int frames, int fps);
void texanim_fromframes(struct TexAnim *anim, int frames);
void tex_incr_anim(struct TexAnimation *tex_anim);
void tex_anim_calc_uv(struct TexAnimation *anim);
void tex_anim_set(struct TexAnimation *anim);
void anim_load(struct anim2d *anim, const char *path); /* Load and start new animation */
void anim_calc(struct anim2d *anim);
void anim_play(struct anim2d *anim);
void anim_setframe(struct anim2d *anim, int frame);
void anim_stop(struct anim2d *anim);
void anim_pause(struct anim2d *anim);
void anim_fwd(struct anim2d *anim);
void anim_bkwd(struct anim2d *anim);
void anim_incr(struct anim2d *anim);
void anim_decr(struct anim2d *anim);
struct glrect tex_get_rect(struct Texture *tex);
cpVect tex_get_dimensions(struct Texture *tex);
struct glrect anim_get_rect(struct anim2d *anim);
int anim_frames(struct TexAnim *a);
#endif

View File

@@ -1,6 +1,5 @@
<meta charset='utf-8' emacsmode='-*- markdown -*-'>
<link rel='stylesheet' href='https://casual-effects.com/markdeep/latest/apidoc.css?'>
<title>Nuklear</title> <!--Page Title-->
# Nuklear
![](https://cloud.githubusercontent.com/assets/8057201/11761525/ae06f0ca-a0c6-11e5-819d-5610b25f6ef4.gif)
## Contents
@@ -90,7 +89,8 @@ NK_PRIVATE | If defined declares all functions as static, s
NK_INCLUDE_FIXED_TYPES | If defined it will include header `<stdint.h>` for fixed sized types otherwise nuklear tries to select the correct type. If that fails it will throw a compiler error and you have to select the correct types yourself.
NK_INCLUDE_DEFAULT_ALLOCATOR | If defined it will include header `<stdlib.h>` and provide additional functions to use this library without caring for memory allocation control and therefore ease memory management.
NK_INCLUDE_STANDARD_IO | If defined it will include header `<stdio.h>` and provide additional functions depending on file loading.
NK_INCLUDE_STANDARD_VARARGS | If defined it will include header <stdio.h> and provide additional functions depending on file loading.
NK_INCLUDE_STANDARD_VARARGS | If defined it will include header <stdarg.h> and provide additional functions depending on file loading.
NK_INCLUDE_STANDARD_BOOL | If defined it will include header `<stdbool.h>` for nk_bool otherwise nuklear defines nk_bool as int.
NK_INCLUDE_VERTEX_BUFFER_OUTPUT | Defining this adds a vertex draw command list backend to this library, which allows you to convert queue commands into vertex draw commands. This is mainly if you need a hardware accessible format for OpenGL, DirectX, Vulkan, Metal,...
NK_INCLUDE_FONT_BAKING | Defining this adds `stb_truetype` and `stb_rect_pack` implementation to this library and provides font baking and rendering. If you already have font handling or do not want to use this font handler you don't have to define it.
NK_INCLUDE_DEFAULT_FONT | Defining this adds the default font: ProggyClean.ttf into this library which can be loaded into a font atlas and allows using this library without having a truetype font
@@ -109,6 +109,7 @@ NK_KEYSTATE_BASED_INPUT | Define this if your backend uses key state for
- NK_INCLUDE_FIXED_TYPES
- NK_INCLUDE_DEFAULT_ALLOCATOR
- NK_INCLUDE_STANDARD_VARARGS
- NK_INCLUDE_STANDARD_BOOL
- NK_INCLUDE_VERTEX_BUFFER_OUTPUT
- NK_INCLUDE_FONT_BAKING
- NK_INCLUDE_DEFAULT_FONT
@@ -132,7 +133,7 @@ Function | Description
NK_ASSERT | If you don't define this, nuklear will use <assert.h> with assert().
NK_MEMSET | You can define this to 'memset' or your own memset implementation replacement. If not nuklear will use its own version.
NK_MEMCPY | You can define this to 'memcpy' or your own memcpy implementation replacement. If not nuklear will use its own version.
NK_SQRT | You can define this to 'sqrt' or your own sqrt implementation replacement. If not nuklear will use its own slow and not highly accurate version.
NK_INV_SQRT | You can define this to your own inverse sqrt implementation replacement. If not nuklear will use its own slow and not highly accurate version.
NK_SIN | You can define this to 'sinf' or your own sine implementation replacement. If not nuklear will use its own approximation implementation.
NK_COS | You can define this to 'cosf' or your own cosine implementation replacement. If not nuklear will use its own approximation implementation.
NK_STRTOD | You can define this to `strtod` or your own string to double conversion implementation replacement. If not defined nuklear will use its own imprecise and possibly unsafe version (does not handle nan or infinity!).
@@ -221,7 +222,7 @@ __nk_set_user_data__| Utility function to pass user data to draw command
Initializes a `nk_context` struct with a default standard library allocator.
Should be used if you don't want to be bothered with memory management in nuklear.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
int nk_init_default(struct nk_context *ctx, const struct nk_user_font *font);
nk_bool nk_init_default(struct nk_context *ctx, const struct nk_user_font *font);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Parameter | Description
------------|---------------------------------------------------------------
@@ -235,7 +236,7 @@ Especially recommended for system with little memory or systems with virtual mem
For the later case you can just allocate for example 16MB of virtual memory
and only the required amount of memory will actually be committed.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
int nk_init_fixed(struct nk_context *ctx, void *memory, nk_size size, const struct nk_user_font *font);
nk_bool nk_init_fixed(struct nk_context *ctx, void *memory, nk_size size, const struct nk_user_font *font);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! Warning
make sure the passed memory block is aligned correctly for `nk_draw_commands`.
@@ -251,7 +252,7 @@ Initializes a `nk_context` struct with memory allocation callbacks for nuklear t
memory from. Used internally for `nk_init_default` and provides a kitchen sink allocation
interface to nuklear. Can be useful for cases like monitoring memory consumption.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
int nk_init(struct nk_context *ctx, struct nk_allocator *alloc, const struct nk_user_font *font);
nk_bool nk_init(struct nk_context *ctx, struct nk_allocator *alloc, const struct nk_user_font *font);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Parameter | Description
------------|---------------------------------------------------------------
@@ -264,7 +265,7 @@ Initializes a `nk_context` struct from two different either fixed or growing
buffers. The first buffer is for allocating draw commands while the second buffer is
used for allocating windows, panels and state tables.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
int nk_init_custom(struct nk_context *ctx, struct nk_buffer *cmds, struct nk_buffer *pool, const struct nk_user_font *font);
nk_bool nk_init_custom(struct nk_context *ctx, struct nk_buffer *cmds, struct nk_buffer *pool, const struct nk_user_font *font);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Parameter | Description
------------|---------------------------------------------------------------
@@ -379,7 +380,7 @@ __y__ | Must hold an integer describing the current mouse cursor y-positio
#### nk_input_key
Mirrors the state of a specific key to nuklear
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
void nk_input_key(struct nk_context*, enum nk_keys key, int down);
void nk_input_key(struct nk_context*, enum nk_keys key, nk_bool down);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Parameter | Description
------------|-----------------------------------------------------------
@@ -389,7 +390,7 @@ __down__ | Must be 0 for key is up and 1 for key is down
#### nk_input_button
Mirrors the state of a specific mouse button to nuklear
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
void nk_input_button(struct nk_context *ctx, enum nk_buttons btn, int x, int y, int down);
void nk_input_button(struct nk_context *ctx, enum nk_buttons btn, int x, int y, nk_bool down);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Parameter | Description
------------|-----------------------------------------------------------
@@ -891,7 +892,7 @@ __NK_MAXIMIZED__| UI section is extended and visible until minimized
Starts a new window; needs to be called every frame for every
window (unless hidden) or otherwise the window gets removed
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
int nk_begin(struct nk_context *ctx, const char *title, struct nk_rect bounds, nk_flags flags);
nk_bool nk_begin(struct nk_context *ctx, const char *title, struct nk_rect bounds, nk_flags flags);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Parameter | Description
------------|-----------------------------------------------------------
@@ -905,7 +906,7 @@ until `nk_end` or `false(0)` otherwise for example if minimized
Extended window start with separated title and identifier to allow multiple
windows with same title but not name
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
int nk_begin_titled(struct nk_context *ctx, const char *name, const char *title, struct nk_rect bounds, nk_flags flags);
nk_bool nk_begin_titled(struct nk_context *ctx, const char *name, const char *title, struct nk_rect bounds, nk_flags flags);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Parameter | Description
------------|-----------------------------------------------------------
@@ -1086,7 +1087,7 @@ Returns if the currently processed window is currently active
!!! WARNING
Only call this function between calls `nk_begin_xxx` and `nk_end`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
int nk_window_has_focus(const struct nk_context *ctx);
nk_bool nk_window_has_focus(const struct nk_context *ctx);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Parameter | Description
------------|-----------------------------------------------------------
@@ -1097,7 +1098,7 @@ Return if the current window is being hovered
!!! WARNING
Only call this function between calls `nk_begin_xxx` and `nk_end`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
int nk_window_is_hovered(struct nk_context *ctx);
nk_bool nk_window_is_hovered(struct nk_context *ctx);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Parameter | Description
------------|-----------------------------------------------------------
@@ -1106,7 +1107,7 @@ Returns `true(1)` if current window is hovered or `false(0)` otherwise
#### nk_window_is_collapsed
Returns if the window with given name is currently minimized/collapsed
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
int nk_window_is_collapsed(struct nk_context *ctx, const char *name);
nk_bool nk_window_is_collapsed(struct nk_context *ctx, const char *name);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Parameter | Description
------------|-----------------------------------------------------------
@@ -1117,7 +1118,7 @@ found or is not minimized
#### nk_window_is_closed
Returns if the window with given name was closed by calling `nk_close`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
int nk_window_is_closed(struct nk_context *ctx, const char *name);
nk_bool nk_window_is_closed(struct nk_context *ctx, const char *name);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Parameter | Description
------------|-----------------------------------------------------------
@@ -1127,7 +1128,7 @@ Returns `true(1)` if current window was closed or `false(0)` window not found or
#### nk_window_is_hidden
Returns if the window with given name is hidden
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
int nk_window_is_hidden(struct nk_context *ctx, const char *name);
nk_bool nk_window_is_hidden(struct nk_context *ctx, const char *name);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Parameter | Description
------------|-----------------------------------------------------------
@@ -1137,7 +1138,7 @@ Returns `true(1)` if current window is hidden or `false(0)` window not found or
#### nk_window_is_active
Same as nk_window_has_focus for some reason
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
int nk_window_is_active(struct nk_context *ctx, const char *name);
nk_bool nk_window_is_active(struct nk_context *ctx, const char *name);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Parameter | Description
------------|-----------------------------------------------------------
@@ -1147,7 +1148,7 @@ Returns `true(1)` if current window is active or `false(0)` window not found or
#### nk_window_is_any_hovered
Returns if the any window is being hovered
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
int nk_window_is_any_hovered(struct nk_context*);
nk_bool nk_window_is_any_hovered(struct nk_context*);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Parameter | Description
------------|-----------------------------------------------------------
@@ -1158,7 +1159,7 @@ Returns if the any window is being hovered or any widget is currently active.
Can be used to decide if input should be processed by UI or your specific input handling.
Example could be UI and 3D camera to move inside a 3D space.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
int nk_item_is_any_active(struct nk_context*);
nk_bool nk_item_is_any_active(struct nk_context*);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Parameter | Description
------------|-----------------------------------------------------------
@@ -1731,6 +1732,14 @@ Parameter | Description
__ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin`
__bounds__ | Rectangle to convert from layout space into screen space
Returns transformed `nk_rect` in layout space coordinates
#### nk_spacer
Spacer is a dummy widget that consumes space as usual but doesn't draw anything
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
void nk_spacer(struct nk_context* );
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Parameter | Description
------------|-----------------------------------------------------------
__ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin`
### Groups
Groups are basically windows inside windows. They allow to subdivide space
in a window to layout widgets as a group. Almost all more complex widget
@@ -1812,7 +1821,7 @@ nk_group_set_scroll | Sets the scroll offset for the given group
#### nk_group_begin
Starts a new widget group. Requires a previous layouting function to specify a pos/size.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
int nk_group_begin(struct nk_context*, const char *title, nk_flags);
nk_bool nk_group_begin(struct nk_context*, const char *title, nk_flags);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Parameter | Description
------------|-----------------------------------------------------------
@@ -1823,7 +1832,7 @@ Returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise
#### nk_group_begin_titled
Starts a new widget group. Requires a previous layouting function to specify a pos/size.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
int nk_group_begin_titled(struct nk_context*, const char *name, const char *title, nk_flags);
nk_bool nk_group_begin_titled(struct nk_context*, const char *name, const char *title, nk_flags);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Parameter | Description
------------|-----------------------------------------------------------
@@ -1844,7 +1853,7 @@ __ctx__ | Must point to an previously initialized `nk_context` struct
starts a new widget group. requires a previous layouting function to specify
a size. Does not keep track of scrollbar.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
int nk_group_scrolled_offset_begin(struct nk_context*, nk_uint *x_offset, nk_uint *y_offset, const char *title, nk_flags flags);
nk_bool nk_group_scrolled_offset_begin(struct nk_context*, nk_uint *x_offset, nk_uint *y_offset, const char *title, nk_flags flags);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Parameter | Description
------------|-----------------------------------------------------------
@@ -1858,7 +1867,7 @@ Returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise
Starts a new widget group. requires a previous
layouting function to specify a size. Does not keep track of scrollbar.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
int nk_group_scrolled_begin(struct nk_context*, struct nk_scroll *off, const char *title, nk_flags);
nk_bool nk_group_scrolled_begin(struct nk_context*, struct nk_scroll *off, const char *title, nk_flags);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Parameter | Description
------------|-----------------------------------------------------------
@@ -1986,7 +1995,7 @@ Returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise
Start a collapsible UI section with internal state management with full
control over internal unique ID used to store state
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
int nk_tree_push_hashed(struct nk_context*, enum nk_tree_type, const char *title, enum nk_collapse_states initial_state, const char *hash, int len,int seed);
nk_bool nk_tree_push_hashed(struct nk_context*, enum nk_tree_type, const char *title, enum nk_collapse_states initial_state, const char *hash, int len,int seed);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Parameter | Description
------------|-----------------------------------------------------------
@@ -2035,7 +2044,7 @@ Returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise
Start a collapsible UI section with internal state management with full
control over internal unique ID used to store state
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
int nk_tree_image_push_hashed(struct nk_context*, enum nk_tree_type, struct nk_image, const char *title, enum nk_collapse_states initial_state, const char *hash, int len,int seed);
nk_bool nk_tree_image_push_hashed(struct nk_context*, enum nk_tree_type, struct nk_image, const char *title, enum nk_collapse_states initial_state, const char *hash, int len,int seed);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Parameter | Description
------------|-----------------------------------------------------------
@@ -2059,7 +2068,7 @@ __ctx__ | Must point to an previously initialized `nk_context` struct after
#### nk_tree_state_push
Start a collapsible UI section with external state management
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
int nk_tree_state_push(struct nk_context*, enum nk_tree_type, const char *title, enum nk_collapse_states *state);
nk_bool nk_tree_state_push(struct nk_context*, enum nk_tree_type, const char *title, enum nk_collapse_states *state);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Parameter | Description
------------|-----------------------------------------------------------
@@ -2071,7 +2080,7 @@ Returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise
#### nk_tree_state_image_push
Start a collapsible UI section with image and label header and external state management
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
int nk_tree_state_image_push(struct nk_context*, enum nk_tree_type, struct nk_image, const char *title, enum nk_collapse_states *state);
nk_bool nk_tree_state_image_push(struct nk_context*, enum nk_tree_type, struct nk_image, const char *title, enum nk_collapse_states *state);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Parameter | Description
------------|-----------------------------------------------------------
@@ -2306,13 +2315,49 @@ X...XXXXXXXXXXXXX...X - "
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
## Changelog
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~none
[date][x.yy.zz]-[description]
-[date]: date on which the change has been pushed
-[x.yy.zz]: Numerical version string representation. Each version number on the right
resets back to zero if version on the left is incremented.
- [x]: Major version with API and library breaking changes
- [yy]: Minor version with non-breaking API and library changes
- [zz]: Bug fix version with no direct changes to API
[date] ([x.y.z]) - [description]
- [date]: date on which the change has been pushed
- [x.y.z]: Version string, represented in Semantic Versioning format
- [x]: Major version with API and library breaking changes
- [y]: Minor version with non-breaking API and library changes
- [z]: Patch version with no direct changes to the API
- 2022/05/27 (4.10.0) - Add nk_input_has_mouse_click_in_button_rect() to fix window move bug
- 2022/04/18 (4.9.7) - Change button behavior when NK_BUTTON_TRIGGER_ON_RELEASE is defined to
only trigger when the mouse position was inside the same button on down
- 2022/02/03 (4.9.6) - Allow overriding the NK_INV_SQRT function, similar to NK_SIN and NK_COS
- 2021/12/22 (4.9.5) - Revert layout bounds not accounting for padding due to regressions
- 2021/12/22 (4.9.4) - Fix checking hovering when window is minimized
- 2021/12/22 (4.09.3) - Fix layout bounds not accounting for padding
- 2021/12/19 (4.09.2) - Update to stb_rect_pack.h v1.01 and stb_truetype.h v1.26
- 2021/12/16 (4.09.1) - Fix the majority of GCC warnings
- 2021/10/16 (4.09.0) - Added nk_spacer() widget
- 2021/09/22 (4.08.6) - Fix "may be used uninitialized" warnings in nk_widget
- 2021/09/22 (4.08.5) - GCC __builtin_offsetof only exists in version 4 and later
- 2021/09/15 (4.08.4) - Fix "'num_len' may be used uninitialized" in nk_do_property
- 2021/09/15 (4.08.3) - Fix "Templates cannot be declared to have 'C' Linkage"
- 2021/09/08 (4.08.2) - Fix warnings in C89 builds
- 2021/09/08 (4.08.1) - Use compiler builtins for NK_OFFSETOF when possible
- 2021/08/17 (4.08.0) - Implemented 9-slice scaling support for widget styles
- 2021/08/16 (4.07.5) - Replace usage of memset in nk_font_atlas_bake with NK_MEMSET
- 2021/08/15 (4.07.4) - Fix conversion and sign conversion warnings
- 2021/08/08 (4.07.3) - Fix crash when baking merged fonts
- 2021/08/08 (4.07.2) - Fix Multiline Edit wrong offset
- 2021/03/17 (4.07.1) - Fix warning about unused parameter
- 2021/03/17 (4.07.0) - Fix nk_property hover bug
- 2021/03/15 (4.06.4) - Change nk_propertyi back to int
- 2021/03/15 (4.06.3) - Update documentation for functions that now return nk_bool
- 2020/12/19 (4.06.2) - Fix additional C++ style comments which are not allowed in ISO C90.
- 2020/10/11 (4.06.1) - Fix C++ style comments which are not allowed in ISO C90.
- 2020/10/07 (4.06.0) - Fix nk_combo return type wrongly changed to nk_bool
- 2020/09/05 (4.05.0) - Use the nk_font_atlas allocator for stb_truetype memory management.
- 2020/09/04 (4.04.1) - Replace every boolean int by nk_bool
- 2020/09/04 (4.04.0) - Add nk_bool with NK_INCLUDE_STANDARD_BOOL
- 2020/06/13 (4.03.1) - Fix nk_pool allocation sizes.
- 2020/06/04 (4.03.0) - Made nk_combo header symbols optional.
- 2020/05/27 (4.02.5) - Fix nk_do_edit: Keep scroll position when re-activating edit widget.
- 2020/05/09 (4.02.4) - Fix nk_menubar height calculation bug
- 2020/05/08 (4.02.3) - Fix missing stdarg.h with NK_INCLUDE_STANDARD_VARARGS
- 2020/04/30 (4.02.2) - Fix nk_edit border drawing bug
- 2020/04/09 (4.02.1) - Removed unused nk_sqrt function to fix compiler warnings
- Fixed compiler warnings if you bring your own methods for
nk_cos/nk_sin/nk_strtod/nk_memset/nk_memcopy/nk_dtoa

View File

@@ -372,7 +372,7 @@ extern "C" {
#elif (defined(_WIN32) || defined(WIN32)) && defined(_MSC_VER)
#define NK_SIZE_TYPE unsigned __int32
#elif defined(__GNUC__) || defined(__clang__)
#if defined(__x86_64__) || defined(__ppc64__)
#if defined(__x86_64__) || defined(__ppc64__) || defined(__aarch64__)
#define NK_SIZE_TYPE unsigned long
#else
#define NK_SIZE_TYPE unsigned int
@@ -387,7 +387,7 @@ extern "C" {
#elif (defined(_WIN32) || defined(WIN32)) && defined(_MSC_VER)
#define NK_POINTER_TYPE unsigned __int32
#elif defined(__GNUC__) || defined(__clang__)
#if defined(__x86_64__) || defined(__ppc64__)
#if defined(__x86_64__) || defined(__ppc64__) || defined(__aarch64__)
#define NK_POINTER_TYPE unsigned long
#else
#define NK_POINTER_TYPE unsigned int
@@ -1127,7 +1127,7 @@ NK_API void nk_input_end(struct nk_context*);
/// cfg.curve_segment_count = 22;
/// cfg.arc_segment_count = 22;
/// cfg.global_alpha = 1.0f;
/// cfg.null = dev->null;
/// cfg.tex_null = dev->tex_null;
/// //
/// // setup buffers and convert
/// struct nk_buffer cmds, verts, idx;
@@ -1177,7 +1177,7 @@ struct nk_convert_config {
unsigned circle_segment_count; /* number of segments used for circles: default to 22 */
unsigned arc_segment_count; /* number of segments used for arcs: default to 22 */
unsigned curve_segment_count; /* number of segments used for curves: default to 22 */
struct nk_draw_null_texture null; /* handle to texture with a white pixel for shape drawing */
struct nk_draw_null_texture tex_null; /* handle to texture with a white pixel for shape drawing */
const struct nk_draw_vertex_layout_element *vertex_layout; /* describes the vertex output format and packing */
nk_size vertex_size; /* sizeof one vertex for vertex packing */
nk_size vertex_alignment; /* vertex alignment: Can be obtained by NK_ALIGNOF */
@@ -6078,7 +6078,6 @@ NK_LIB void nk_property(struct nk_context *ctx, const char *name, struct nk_prop
#define STB_RECT_PACK_IMPLEMENTATION
#define STB_TRUETYPE_IMPLEMENTATION
#define STBTT_STATIC
/* Allow consumer to define own STBTT_malloc/STBTT_free, and use the font atlas' allocator otherwise */
#ifndef STBTT_malloc
@@ -8440,7 +8439,6 @@ nk_str_append_text_utf8(struct nk_str *str, const char *text, int len)
NK_API int
nk_str_append_str_utf8(struct nk_str *str, const char *text)
{
int runes = 0;
int byte_len = 0;
int num_runes = 0;
int glyph_len = 0;
@@ -8454,7 +8452,7 @@ nk_str_append_str_utf8(struct nk_str *str, const char *text)
num_runes++;
}
nk_str_append_text_char(str, text, byte_len);
return runes;
return num_runes;
}
NK_API int
nk_str_append_text_runes(struct nk_str *str, const nk_rune *text, int len)
@@ -8569,7 +8567,6 @@ nk_str_insert_text_utf8(struct nk_str *str, int pos, const char *text, int len)
NK_API int
nk_str_insert_str_utf8(struct nk_str *str, int pos, const char *text)
{
int runes = 0;
int byte_len = 0;
int num_runes = 0;
int glyph_len = 0;
@@ -8583,7 +8580,7 @@ nk_str_insert_str_utf8(struct nk_str *str, int pos, const char *text)
num_runes++;
}
nk_str_insert_at_rune(str, pos, text, byte_len);
return runes;
return num_runes;
}
NK_API int
nk_str_insert_text_runes(struct nk_str *str, int pos, const nk_rune *runes, int len)
@@ -9564,7 +9561,7 @@ nk_draw_list_add_clip(struct nk_draw_list *list, struct nk_rect rect)
NK_ASSERT(list);
if (!list) return;
if (!list->cmd_count) {
nk_draw_list_push_command(list, rect, list->config.null.texture);
nk_draw_list_push_command(list, rect, list->config.tex_null.texture);
} else {
struct nk_draw_command *prev = nk_draw_list_command_last(list);
if (prev->elem_count == 0)
@@ -9919,7 +9916,7 @@ nk_draw_list_stroke_poly_line(struct nk_draw_list *list, const struct nk_vec2 *p
/* fill vertices */
for (i = 0; i < points_count; ++i) {
const struct nk_vec2 uv = list->config.null.uv;
const struct nk_vec2 uv = list->config.tex_null.uv;
vtx = nk_draw_vertex(vtx, &list->config, points[i], uv, col);
vtx = nk_draw_vertex(vtx, &list->config, temp[i*2+0], uv, col_trans);
vtx = nk_draw_vertex(vtx, &list->config, temp[i*2+1], uv, col_trans);
@@ -9984,7 +9981,7 @@ nk_draw_list_stroke_poly_line(struct nk_draw_list *list, const struct nk_vec2 *p
/* add vertices */
for (i = 0; i < points_count; ++i) {
const struct nk_vec2 uv = list->config.null.uv;
const struct nk_vec2 uv = list->config.tex_null.uv;
vtx = nk_draw_vertex(vtx, &list->config, temp[i*4+0], uv, col_trans);
vtx = nk_draw_vertex(vtx, &list->config, temp[i*4+1], uv, col);
vtx = nk_draw_vertex(vtx, &list->config, temp[i*4+2], uv, col);
@@ -10005,7 +10002,7 @@ nk_draw_list_stroke_poly_line(struct nk_draw_list *list, const struct nk_vec2 *p
for (i1 = 0; i1 < count; ++i1) {
float dx, dy;
const struct nk_vec2 uv = list->config.null.uv;
const struct nk_vec2 uv = list->config.tex_null.uv;
const nk_size i2 = ((i1+1) == points_count) ? 0 : i1 + 1;
const struct nk_vec2 p1 = points[i1];
const struct nk_vec2 p2 = points[i2];
@@ -10115,7 +10112,7 @@ nk_draw_list_fill_poly_convex(struct nk_draw_list *list,
/* add vertices + indexes */
for (i0 = points_count-1, i1 = 0; i1 < points_count; i0 = i1++) {
const struct nk_vec2 uv = list->config.null.uv;
const struct nk_vec2 uv = list->config.tex_null.uv;
struct nk_vec2 n0 = normals[i0];
struct nk_vec2 n1 = normals[i1];
struct nk_vec2 dm = nk_vec2_muls(nk_vec2_add(n0, n1), 0.5f);
@@ -10152,7 +10149,7 @@ nk_draw_list_fill_poly_convex(struct nk_draw_list *list,
if (!vtx || !ids) return;
for (i = 0; i < vtx_count; ++i)
vtx = nk_draw_vertex(vtx, &list->config, points[i], list->config.null.uv, col);
vtx = nk_draw_vertex(vtx, &list->config, points[i], list->config.tex_null.uv, col);
for (i = 2; i < points_count; ++i) {
ids[0] = (nk_draw_index)index;
ids[1] = (nk_draw_index)(index+ i - 1);
@@ -10181,8 +10178,8 @@ nk_draw_list_path_line_to(struct nk_draw_list *list, struct nk_vec2 pos)
nk_draw_list_add_clip(list, nk_null_rect);
cmd = nk_draw_list_command_last(list);
if (cmd && cmd->texture.ptr != list->config.null.texture.ptr)
nk_draw_list_push_image(list, list->config.null.texture);
if (cmd && cmd->texture.ptr != list->config.tex_null.texture.ptr)
nk_draw_list_push_image(list, list->config.tex_null.texture);
points = nk_draw_list_alloc_path(list, 1);
if (!points) return;
@@ -10384,7 +10381,7 @@ nk_draw_list_fill_rect_multi_color(struct nk_draw_list *list, struct nk_rect rec
NK_ASSERT(list);
if (!list) return;
nk_draw_list_push_image(list, list->config.null.texture);
nk_draw_list_push_image(list, list->config.tex_null.texture);
index = (nk_draw_index)list->vertex_count;
vtx = nk_draw_list_alloc_vertices(list, 4);
idx = nk_draw_list_alloc_elements(list, 6);
@@ -10394,10 +10391,10 @@ nk_draw_list_fill_rect_multi_color(struct nk_draw_list *list, struct nk_rect rec
idx[2] = (nk_draw_index)(index+2); idx[3] = (nk_draw_index)(index+0);
idx[4] = (nk_draw_index)(index+2); idx[5] = (nk_draw_index)(index+3);
vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(rect.x, rect.y), list->config.null.uv, col_left);
vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(rect.x + rect.w, rect.y), list->config.null.uv, col_top);
vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(rect.x + rect.w, rect.y + rect.h), list->config.null.uv, col_right);
vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(rect.x, rect.y + rect.h), list->config.null.uv, col_bottom);
vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(rect.x, rect.y), list->config.tex_null.uv, col_left);
vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(rect.x + rect.w, rect.y), list->config.tex_null.uv, col_top);
vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(rect.x + rect.w, rect.y + rect.h), list->config.tex_null.uv, col_right);
vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(rect.x, rect.y + rect.h), list->config.tex_null.uv, col_bottom);
}
NK_API void
nk_draw_list_fill_triangle(struct nk_draw_list *list, struct nk_vec2 a,
@@ -16513,7 +16510,7 @@ nk_font_chinese_glyph_ranges(void)
0x3000, 0x30FF,
0x31F0, 0x31FF,
0xFF00, 0xFFEF,
0x4e00, 0x9FAF,
0x4E00, 0x9FAF,
0
};
return ranges;
@@ -16622,7 +16619,7 @@ nk_font_bake_pack(struct nk_font_baker *baker,
struct stbtt_fontinfo *font_info = &baker->build[i++].info;
font_info->userdata = alloc;
if (!stbtt_InitFont(font_info, (const unsigned char*)it->ttf_blob, 0))
if (!stbtt_InitFont(font_info, (const unsigned char*)it->ttf_blob, stbtt_GetFontOffsetForIndex((const unsigned char*)it->ttf_blob, 0)))
return nk_false;
} while ((it = it->n) != config_iter);
}
@@ -17704,20 +17701,20 @@ failed:
}
NK_API void
nk_font_atlas_end(struct nk_font_atlas *atlas, nk_handle texture,
struct nk_draw_null_texture *null)
struct nk_draw_null_texture *tex_null)
{
int i = 0;
struct nk_font *font_iter;
NK_ASSERT(atlas);
if (!atlas) {
if (!null) return;
null->texture = texture;
null->uv = nk_vec2(0.5f,0.5f);
if (!tex_null) return;
tex_null->texture = texture;
tex_null->uv = nk_vec2(0.5f,0.5f);
}
if (null) {
null->texture = texture;
null->uv.x = (atlas->custom.x + 0.5f)/(float)atlas->tex_width;
null->uv.y = (atlas->custom.y + 0.5f)/(float)atlas->tex_height;
if (tex_null) {
tex_null->texture = texture;
tex_null->uv.x = (atlas->custom.x + 0.5f)/(float)atlas->tex_width;
tex_null->uv.y = (atlas->custom.y + 0.5f)/(float)atlas->tex_height;
}
for (font_iter = atlas->fonts; font_iter; font_iter = font_iter->next) {
font_iter->texture = texture;
@@ -26163,7 +26160,7 @@ nk_textedit_text(struct nk_text_edit *state, const char *text, int total_len)
text+text_len, 1))
{
nk_textedit_makeundo_insert(state, state->cursor, 1);
++state->cursor;
state->cursor = NK_MIN(state->cursor + 1, state->string.len);
state->has_preferred_x = 0;
}
}
@@ -29657,6 +29654,12 @@ nk_tooltipfv(struct nk_context *ctx, const char *fmt, va_list args)
/// - [y]: Minor version with non-breaking API and library changes
/// - [z]: Patch version with no direct changes to the API
///
/// - 2022/12/17 (4.10.5) - Fix nk_font_bake_pack() using TTC font offset incorrectly
/// - 2022/10/24 (4.10.4) - Fix nk_str_{append,insert}_str_utf8 always returning 0
/// - 2022/09/03 (4.10.3) - Renamed the `null` texture variable to `tex_null`
/// - 2022/08/01 (4.10.2) - Fix Apple Silicon with incorrect NK_SITE_TYPE and NK_POINTER_TYPE
/// - 2022/08/01 (4.10.1) - Fix cursor jumping back to beginning of text when typing more than
/// nk_edit_xxx limit
/// - 2022/05/27 (4.10.0) - Add nk_input_has_mouse_click_in_button_rect() to fix window move bug
/// - 2022/04/18 (4.9.7) - Change button behavior when NK_BUTTON_TRIGGER_ON_RELEASE is defined to
/// only trigger when the mouse position was inside the same button on down

Some files were not shown because too many files have changed in this diff Show More