// // 3d-glue.c // Extension // // Created by Dave Hayden on 9/19/15. // Copyright © 2015 Panic, Inc. All rights reserved. // #include #include "luaglue.h" #include "mini3d.h" #include "3dmath.h" #include "shape.h" #include "scene.h" static PlaydateAPI* pd = NULL; static void* get3DObj(int n, char* type) { void* obj = pd->lua->getArgObject(n, type, NULL); if ( obj == NULL ) pd->system->error("object of type %s not found at stack position %i", type, n); return obj; } static Scene3D* getScene(int n) { return get3DObj(n, "lib3d.scene"); } static Scene3DNode* getSceneNode(int n) { return get3DObj(n, "lib3d.scenenode"); } static Shape3D* getShape(int n) { return get3DObj(n, "lib3d.shape"); } static Point3D* getPoint(int n) { return get3DObj(n, "lib3d.point"); } static Matrix3D* getMatrix(int n) { return get3DObj(n, "lib3d.matrix"); } /// Scene static int scene_new(lua_State* L) { Scene3D* scene = m3d_malloc(sizeof(Scene3D)); Scene3D_init(scene); pd->lua->pushObject(scene, "lib3d.scene", 0); return 1; } static int scene_gc(lua_State* L) { Scene3D* scene = getScene(1); Scene3D_deinit(scene); m3d_free(scene); return 0; } static int scene_getRoot(lua_State* L) { Scene3D* scene = getScene(1); pd->lua->pushObject(Scene3D_getRootNode(scene), "lib3d.scenenode", 0); return 1; } static int scene_draw(lua_State* L) { Scene3D* scene = getScene(1); Scene3D_draw(scene, pd->graphics->getFrame(), LCD_ROWSIZE); pd->graphics->markUpdatedRows(0, LCD_ROWS-1); // XXX return 0; } static int scene_drawNode(lua_State* L) { Scene3D* scene = getScene(1); Scene3DNode* node = getSceneNode(2); Scene3D_drawNode(scene, node, pd->graphics->getFrame(), LCD_ROWSIZE); pd->graphics->markUpdatedRows(0, LCD_ROWS-1); // XXX return 0; } static int scene_setLight(lua_State* L) { Scene3D* scene = getScene(1); float x = pd->lua->getArgFloat(2); float y = pd->lua->getArgFloat(3); float z = pd->lua->getArgFloat(4); Scene3D_setGlobalLight(scene, Vector3DMake(x, y, z)); return 0; } static int scene_setCenter(lua_State* L) { Scene3D* scene = getScene(1); float x = pd->lua->getArgFloat(2); float y = pd->lua->getArgFloat(3); Scene3D_setCenter(scene, x, y); return 0; } static Point3D cameraOrigin = { .x = 0, .y = 0, .z = -1 }; static Point3D cameraLookat = { .x = 0, .y = 0, .z = 0 }; static float cameraScale = 1.0; static Vector3D cameraUp = { .dx = 0, .dy = -1, .dz = 0 }; static int scene_setCameraOrigin(lua_State* L) { Scene3D* scene = getScene(1); cameraOrigin.x = pd->lua->getArgFloat(2); cameraOrigin.y = pd->lua->getArgFloat(3); cameraOrigin.z = pd->lua->getArgFloat(4); Scene3D_setCamera(scene, cameraOrigin, cameraLookat, cameraScale, cameraUp); return 0; } static int scene_setCameraTarget(lua_State* L) { Scene3D* scene = getScene(1); cameraLookat.x = pd->lua->getArgFloat(2); cameraLookat.y = pd->lua->getArgFloat(3); cameraLookat.z = pd->lua->getArgFloat(4); Scene3D_setCamera(scene, cameraOrigin, cameraLookat, cameraScale, cameraUp); return 0; } static int scene_setCameraScale(lua_State* L) { Scene3D* scene = getScene(1); cameraScale = pd->lua->getArgFloat(2); Scene3D_setCamera(scene, cameraOrigin, cameraLookat, cameraScale, cameraUp); return 0; } static int scene_setCameraUp(lua_State* L) { Scene3D* scene = getScene(1); cameraUp.dx = pd->lua->getArgFloat(2); cameraUp.dy = pd->lua->getArgFloat(3); cameraUp.dz = pd->lua->getArgFloat(4); Scene3D_setCamera(scene, cameraOrigin, cameraLookat, cameraScale, cameraUp); return 0; } static const lua_reg lib3DScene[] = { { "__gc", scene_gc }, { "new", scene_new }, { "draw", scene_draw }, { "drawNode", scene_drawNode }, { "getRootNode", scene_getRoot }, { "setLight", scene_setLight }, { "setCenter", scene_setCenter }, { "setCameraOrigin", scene_setCameraOrigin }, { "setCameraScale", scene_setCameraScale }, { "setCameraTarget", scene_setCameraTarget }, { "setCameraUp", scene_setCameraUp }, { NULL, NULL } }; /// Node static int node_gc(lua_State* L) { // XXX - release shapes return 0; } static int node_addShape(lua_State* L) { Scene3DNode* node = getSceneNode(1); Shape3D* shape = getShape(2); Matrix3D* m = pd->lua->getArgObject(3, "lib3d.matrix", NULL); if ( m != NULL ) Scene3DNode_addShapeWithTransform(node, shape, *m); else if ( pd->lua->getArgCount() > 2 ) { Vector3D v = { 0, 0, 0 }; v.dx = pd->lua->getArgFloat(3); v.dy = pd->lua->getArgFloat(4); v.dz = pd->lua->getArgFloat(5); Scene3DNode_addShapeWithOffset(node, shape, v); } else Scene3DNode_addShape(node, shape); //pd->lua->retainObject(shapeobj); return 0; } static int node_makeChildNode(lua_State* L) { Scene3DNode* node = getSceneNode(1); Scene3DNode* scene = Scene3DNode_newChild(node); pd->lua->pushObject(scene, "lib3d.scenenode", 0); return 1; } static int node_setTransform(lua_State* L) { Scene3DNode* node = getSceneNode(1); Matrix3D* xform = getMatrix(2); Scene3DNode_setTransform(node, xform); return 0; } static int node_addTransform(lua_State* L) { Scene3DNode* node = getSceneNode(1); Matrix3D* xform = getMatrix(2); Scene3DNode_addTransform(node, xform); return 0; } static int node_translateBy(lua_State* L) { Scene3DNode* node = getSceneNode(1); Matrix3D xform = identityMatrix; xform.dx = pd->lua->getArgFloat(2); xform.dy = pd->lua->getArgFloat(3); xform.dz = pd->lua->getArgFloat(4); Scene3DNode_addTransform(node, &xform); return 0; } static int node_scaleBy(lua_State* L) { Scene3DNode* node = getSceneNode(1); Matrix3D xform = node->transform; float sx, sy, sz; if ( pd->lua->getArgCount() > 2 ) { sx = pd->lua->getArgFloat(2); sy = pd->lua->getArgFloat(3); sz = pd->lua->getArgFloat(4); } else sx = sy = sz = pd->lua->getArgFloat(2); xform.isIdentity = 0; xform.m[0][0] *= sx; xform.m[1][0] *= sx; xform.m[2][0] *= sx; xform.m[0][1] *= sy; xform.m[1][1] *= sy; xform.m[2][1] *= sy; xform.m[0][2] *= sz; xform.m[1][2] *= sz; xform.m[2][2] *= sz; xform.dx *= sx; xform.dy *= sy; xform.dz *= sz; xform.inverting = (sx * sy * sz < 0); Scene3DNode_setTransform(node, &xform); return 0; } static int node_setColorBias(lua_State* L) { Scene3DNode* node = getSceneNode(1); Scene3DNode_setColorBias(node, pd->lua->getArgFloat(2)); return 0; } static int node_setFilled(lua_State* L) { Scene3DNode* node = getSceneNode(1); int flag = pd->lua->getArgBool(2); RenderStyle style = Scene3DNode_getRenderStyle(node); if ( flag ) style |= kRenderFilled; else style &= ~kRenderFilled; Scene3DNode_setRenderStyle(node, style); return 0; } static int node_setWireframeMode(lua_State* L) { Scene3DNode* node = getSceneNode(1); int mode = pd->lua->getArgInt(2); RenderStyle style = Scene3DNode_getRenderStyle(node); if ( mode > 0 ) { style |= kRenderWireframe; if ( mode == 1 ) style &= ~kRenderWireframeBack; else style |= kRenderWireframeBack; } else style &= ~kRenderWireframe; Scene3DNode_setRenderStyle(node, style); return 0; } static int node_setWireframeColor(lua_State* L) { Scene3DNode* node = getSceneNode(1); int color = pd->lua->getArgInt(2); RenderStyle style = Scene3DNode_getRenderStyle(node); if ( color ) style |= kRenderWireframeWhite; else style &= ~kRenderWireframeWhite; Scene3DNode_setRenderStyle(node, style); return 0; } static int node_setVisible(lua_State* L) { Scene3DNode* node = getSceneNode(1); Scene3DNode_setVisible(node, pd->lua->getArgBool(2)); return 0; } static const lua_reg lib3DNode[] = { { "__gc", node_gc }, { "addChildNode", node_makeChildNode }, { "addShape", node_addShape }, { "addTransform", node_addTransform }, { "setTransform", node_setTransform }, { "translateBy", node_translateBy }, { "scaleBy", node_scaleBy }, { "setColorBias", node_setColorBias }, { "setFilled", node_setFilled }, { "setWireframeMode", node_setWireframeMode }, { "setWireframeColor", node_setWireframeColor }, { "setVisible", node_setVisible }, { NULL, NULL } }; /// Shape static int shape_new(lua_State* L) { Shape3D* shape = m3d_malloc(sizeof(Shape3D)); Shape3D_init(shape); Shape3D_retain(shape); pd->lua->pushObject(shape, "lib3d.shape", 0); return 1; } static int shape_gc(lua_State* L) { Shape3D* shape = getShape(1); Shape3D_release(shape); return 0; } static int shape_addFace(lua_State* L) { Shape3D* shape = getShape(1); Point3D* a = getPoint(2); Point3D* b = getPoint(3); Point3D* c = getPoint(4); Point3D* d = NULL; const char* type; float color = 0; if ( pd->lua->getArgType(5, &type) == kTypeObject && strcmp(type, "lib3d.point") == 0 ) { d = getPoint(5); color = pd->lua->getArgFloat(6); } else color = pd->lua->getArgFloat(5); Shape3D_addFace(shape, a, b, c, d, color); return 0; } static int shape_setClosed(lua_State* L) { Shape3D_setClosed(getShape(1), pd->lua->getArgBool(2)); return 0; } #if ENABLE_ORDERING_TABLE static int shape_setOrderTableSize(lua_State* L) { Shape3D_setOrderTableSize(getShape(1), pd->lua->getArgInt(2)); return 0; } #endif static const lua_reg lib3DShape[] = { { "new", shape_new }, { "__gc", shape_gc }, { "addFace", shape_addFace }, { "setClosed", shape_setClosed }, #if ENABLE_ORDERING_TABLE { "setOrderTableSize", shape_setOrderTableSize, }, #endif { NULL, NULL } }; /// Point static int point_new(lua_State* L) { Point3D* p = m3d_malloc(sizeof(Point3D)); p->x = pd->lua->getArgFloat(1); p->y = pd->lua->getArgFloat(2); p->z = pd->lua->getArgFloat(3); pd->lua->pushObject(p, "lib3d.point", 0); return 1; } static int point_gc(lua_State* L) { Point3D* p = getPoint(1); m3d_free(p); return 0; } static int point_index(lua_State* L) { Point3D* p = getPoint(1); const char* arg = pd->lua->getArgString(2); if ( strcmp(arg, "x") == 0 ) pd->lua->pushFloat(p->x); else if ( strcmp(arg, "y") == 0 ) pd->lua->pushFloat(p->y); else if ( strcmp(arg, "z") == 0 ) pd->lua->pushFloat(p->z); else pd->lua->pushNil(); return 1; } static int point_newindex(lua_State* L) { Point3D* p = getPoint(1); const char* arg = pd->lua->getArgString(2); if ( strcmp(arg, "x") == 0 ) p->x = pd->lua->getArgFloat(3); else if ( strcmp(arg, "y") == 0 ) p->y = pd->lua->getArgFloat(3); else if ( strcmp(arg, "z") == 0 ) p->z = pd->lua->getArgFloat(3); return 0; } static int point_mul(lua_State* L) { Point3D* p = getPoint(1); Matrix3D* m = getMatrix(2); Point3D* p2 = m3d_malloc(sizeof(Point3D)); *p2 = Matrix3D_apply(*m, *p); pd->lua->pushObject(p2, "lib3d.point", 0); return 1; } static const lua_reg lib3DPoint[] = { { "new", point_new }, { "__gc", point_gc }, { "__index", point_index }, { "__newindex", point_newindex }, { "__mul", point_mul }, { NULL, NULL } }; /// Matrix static int matrix_gc(lua_State* L) { Matrix3D* m = getMatrix(1); m3d_free(m); return 0; } static int matrix_mul(lua_State* L) { Matrix3D* l = getMatrix(1); Matrix3D* r = getMatrix(2); Matrix3D* m = m3d_malloc(sizeof(Matrix3D)); *m = Matrix3D_multiply(*l, *r); pd->lua->pushObject(m, "lib3d.matrix", 0); return 1; } static int matrix_new(lua_State* L) { Matrix3D* p = m3d_malloc(sizeof(Matrix3D)); p->isIdentity = 0; p->m[0][0] = pd->lua->getArgFloat(1); p->m[0][1] = pd->lua->getArgFloat(2); p->m[0][2] = pd->lua->getArgFloat(3); p->m[1][0] = pd->lua->getArgFloat(4); p->m[1][1] = pd->lua->getArgFloat(5); p->m[1][2] = pd->lua->getArgFloat(6); p->m[2][0] = pd->lua->getArgFloat(7); p->m[2][1] = pd->lua->getArgFloat(8); p->m[2][2] = pd->lua->getArgFloat(9); p->dx = pd->lua->getArgFloat(10); p->dy = pd->lua->getArgFloat(11); p->dz = pd->lua->getArgFloat(12); p->inverting = Matrix3D_getDeterminant(p) < 0; pd->lua->pushObject(p, "lib3d.matrix", 0); return 1; } static int matrix_newRotation(lua_State* L) { Matrix3D* p = m3d_malloc(sizeof(Matrix3D)); #undef M_PI #define M_PI 3.14159265358979323846f float angle = pd->lua->getArgFloat(1); float c = cosf(angle * M_PI / 180); float s = sinf(angle * M_PI / 180); float x = pd->lua->getArgFloat(2); float y = pd->lua->getArgFloat(3); float z = pd->lua->getArgFloat(4); float d = sqrtf(x * x + y * y + z * z); x /= d; y /= d; z /= d; p->isIdentity = 0; p->inverting = 0; p->m[0][0] = c + x * x * (1-c); p->m[0][1] = x * y * (1-c) - z * s; p->m[0][2] = x * z * (1-c) + y * s; p->m[1][0] = y * x * (1-c) + z * s; p->m[1][1] = c + y * y * (1-c); p->m[1][2] = y * z * (1-c) - x * s; p->m[2][0] = z * x * (1-c) - y * s; p->m[2][1] = z * y * (1-c) + x * s; p->m[2][2] = c + z * z * (1-c); p->dx = p->dy = p->dz = 0; pd->lua->pushObject(p, "lib3d.matrix", 0); return 1; } static int matrix_addTranslation(lua_State* L) { Matrix3D* l = getMatrix(1); l->dx += pd->lua->getArgFloat(2); l->dy += pd->lua->getArgFloat(3); l->dz += pd->lua->getArgFloat(4); return 0; } static const lua_reg lib3DMatrix[] = { { "__gc", matrix_gc }, { "__mul", matrix_mul }, { "new", matrix_new }, { "newRotation", matrix_newRotation }, { "addTranslation", matrix_addTranslation }, { NULL, NULL } }; void register3D(PlaydateAPI* playdate) { pd = playdate; const char* err; if (!pd->lua->registerClass("lib3d.scene", lib3DScene, NULL, 0, &err)) pd->system->logToConsole("%s:%i: registerClass failed, %s", __FILE__, __LINE__, err); if (!pd->lua->registerClass("lib3d.scenenode", lib3DNode, NULL, 0, &err)) pd->system->logToConsole("%s:%i: registerClass failed, %s", __FILE__, __LINE__, err); if (!pd->lua->registerClass("lib3d.shape", lib3DShape, NULL, 0, &err)) pd->system->logToConsole("%s:%i: registerClass failed, %s", __FILE__, __LINE__, err); if (!pd->lua->registerClass("lib3d.point", lib3DPoint, NULL, 0, &err)) pd->system->logToConsole("%s:%i: registerClass failed, %s", __FILE__, __LINE__, err); if (!pd->lua->registerClass("lib3d.matrix", lib3DMatrix, NULL, 0, &err)) pd->system->logToConsole("%s:%i: registerClass failed, %s", __FILE__, __LINE__, err); mini3d_setRealloc(pd->system->realloc); }