M README.md => README.md +0 -1
@@ 10,7 10,6 @@ support the to-be-released Playdate handheld console.
## TODO
- Use ints for rasterization
-- Implement [Pineda triangle raster algorithm][pineda]
- Use [guard-band clipping][clipping]
- Add sub-pixel precision
- Gouraud shading
M src/game.c => src/game.c +5 -1
@@ 43,7 43,7 @@ int main(void)
// one-shot
// UpdateScene(scene, 1);
- // ClearScreen(gameRenderer);
+ // ClearScreen(gameRenderer->viewport);
// RenderScene(scene, gameRenderer);
/* variables for perf statistics */
@@ 103,10 103,14 @@ Scene *MoonWorld(void)
{
Scene *scene = NewScene();
SceneObject *obj = CreateSceneObject(scene, "assets/cube.obj", BLACK);
+ obj->renderable->color = LT_GRAY;
+ SceneObject *obj2 = CloneSceneObject(scene, obj);
+ obj2->renderable->color = DK_GRAY;
PlaceModel(obj->model, V(0, 0, -10));
Spin(obj->physics, V(1, 1, 0), 0.1);
Spin(obj->physics, V(0, 1, 1), 0.05);
Spin(obj->physics, V(0, 1, 0), 0.1);
+ PlaceModel(obj2->model, V(3, 0, -15));
// InitParticleSystem(scene);
// for (int i = 0; i < 1000; i++) {
M src/mesh.c => src/mesh.c +0 -21
@@ 78,27 78,6 @@ void PrintPolygon(int *polygon, Vertex *vertices)
PrintVec(*PolygonVertex(polygon, vertices, i));
}
printf("\n");
- fflush(stdout);
-}
-
-Rect PolygonBounds(int *polygon, Vertex *vertices)
-{
- Rect r = { vertices[0].x, vertices[0].y, vertices[0].x, vertices[0].y };
- for (int i = 0; i < NumPolygonVertices(polygon); i++) {
- Vertex *v = PolygonVertex(polygon, vertices, i);
- if (v->x < r.left) r.left = v->x;
- if (v->x > r.right) r.right = v->x;
- if (v->y < r.top) r.top = v->y;
- if (v->y > r.bottom) r.bottom = v->y;
- }
- return r;
-}
-
-void PrintRect(Rect r)
-{
- printf("%6.2f, %6.2f┌───┐%6.2f, %6.2f\n", r.top, r.left, r.top, r.right);
- printf(" │ │\n");
- printf("%6.2f, %6.2f└───┘%6.2f, %6.2f\n", r.bottom, r.left, r.bottom, r.right);
}
void Triangularize(int *polygon, Mesh *mesh)
M src/mesh.h => src/mesh.h +0 -9
@@ 3,13 3,6 @@
#include "vector.h"
#include "pool.h"
-typedef struct Rect {
- float top;
- float left;
- float right;
- float bottom;
-} Rect;
-
typedef struct Mesh {
Vertex *vertices;
int *faces;
@@ 33,6 26,4 @@ Vertex *NewVertex(Vertex *pool);
int *NewPolygon(int *pool);
void PrintPolygon(int *polygon, Vertex *vertices);
-Rect PolygonBounds(int *polygon, Vertex *vertices);
-void PrintRect(Rect r);
void Triangularize(int *polygon, Mesh *mesh);
M src/renderable.c => src/renderable.c +2 -2
@@ 59,8 59,8 @@ void Render(Renderable renderable, Renderer *renderer, Transform camera_transfor
i < PoolTotal(renderMesh.faces);
i += NumPolygonVertices(polygon)+1, NextPolygon(polygon)) {
if (NumPolygonVertices(polygon) > 0) {
- RasterizePolygon(polygon, renderMesh.vertices, renderer->viewport);
- WireframePolygon(polygon, renderMesh.vertices, renderer->viewport);
+ DrawPolygon(polygon, renderMesh.vertices, renderable.color, renderer->viewport);
+ // WireframePolygon(polygon, renderMesh.vertices, renderer->viewport);
}
}
}
M src/scene.c => src/scene.c +10 -0
@@ 50,6 50,16 @@ SceneObject *NewSceneObject(SceneObject *pool, Model *model, Renderable *rendera
return obj;
}
+SceneObject *CloneSceneObject(Scene *scene, SceneObject *obj)
+{
+ Model *model = NewModel(scene->model_pool);
+ Renderable *renderable = NewRenderable(scene->renderable_pool, model, obj->renderable->color);
+ renderable->mesh = obj->renderable->mesh;
+ Physics *physics = NewPhysics(scene->physics_pool, model);
+ SceneObject *clone = NewSceneObject(scene->objects, model, renderable, physics);
+ return clone;
+}
+
void InitParticleSystem(Scene *scene)
/* Activates a Scene's particle pool. Presence of this pool will also enable
particle processing.
M src/scene.h => src/scene.h +1 -0
@@ 26,6 26,7 @@ Scene *NewScene(void);
SceneObject *CreateSceneObject(Scene *scene, const char *meshFile, Color color);
SceneObject *NewSceneObjectPool(void);
SceneObject *NewSceneObject(SceneObject *pool, Model *model, Renderable *renderable, Physics *physics);
+SceneObject *CloneSceneObject(Scene *scene, SceneObject *obj);
void InitParticleSystem(Scene *scene);
void UpdateScene(Scene *scene, int dt);
void RenderScene(Scene *scene, Renderer *renderer);
M src/viewport.c => src/viewport.c +82 -15
@@ 2,6 2,8 @@
#include "mesh.h"
#include <math.h>
#include <stdlib.h>
+#include <assert.h>
+#include <stdio.h>
Viewport *NewViewport(Pixel *pixels, Color background_color, int width, int height)
{
@@ 37,21 39,49 @@ void ClearScreen(Viewport *viewport)
}
}
-void RasterizePolygon(int *polygon, Vertex *vertices, Viewport *viewport)
+void DrawPolygon(int *polygon, Vertex *vertices, Color color, Viewport *viewport)
{
+ assert(NumPolygonVertices(polygon) == 3);
Rect bounding_box = PolygonBounds(polygon, vertices);
- DrawBoundingBox(bounding_box, viewport);
+ EdgeTracker a = TrackEdge(PolygonVertex(polygon, vertices, 0), PolygonVertex(polygon, vertices, 1), V(bounding_box.left, bounding_box.bottom, 0));
+ EdgeTracker b = TrackEdge(PolygonVertex(polygon, vertices, 1), PolygonVertex(polygon, vertices, 2), V(bounding_box.left, bounding_box.bottom, 0));
+ EdgeTracker c = TrackEdge(PolygonVertex(polygon, vertices, 2), PolygonVertex(polygon, vertices, 0), V(bounding_box.left, bounding_box.bottom, 0));
+
+ for (int y = bounding_box.bottom; y < bounding_box.top; y += 2) {
+ for (int x = bounding_box.left; x <= bounding_box.right; x++) {
+ if (a.value < 0 && b.value < 0 && c.value < 0) {
+ // TryWritePixel(x, y, z, color, viewport);
+ WritePixel(x, y, color, viewport);
+ }
+ a.value += a.dy;
+ b.value += b.dy;
+ c.value += c.dy;
+ }
+ a.value -= a.dx;
+ b.value -= b.dx;
+ c.value -= c.dx;
+ for (int x = bounding_box.right; x >= bounding_box.left; x--) {
+ if (a.value < 0 && b.value < 0 && c.value < 0) {
+ WritePixel(x, y + 1, color, viewport);
+ }
+ a.value -= a.dy;
+ b.value -= b.dy;
+ c.value -= c.dy;
+ }
+ a.value -= a.dx;
+ b.value -= b.dx;
+ c.value -= c.dx;
+ }
}
void DrawBoundingBox(Rect bounding_box, Viewport *viewport)
{
- RasterLine(V(bounding_box.left, bounding_box.top, 0), V(bounding_box.right, bounding_box.top, 0), GRAY, viewport);
- RasterLine(V(bounding_box.right, bounding_box.top, 0), V(bounding_box.right, bounding_box.bottom, 0), GRAY, viewport);
- RasterLine(V(bounding_box.left, bounding_box.bottom, 0), V(bounding_box.right, bounding_box.bottom, 0), GRAY, viewport);
- RasterLine(V(bounding_box.left, bounding_box.top, 0), V(bounding_box.left, bounding_box.bottom, 0), GRAY, viewport);
+ DrawLine(V(bounding_box.left, bounding_box.top, 0), V(bounding_box.right, bounding_box.top, 0), GRAY, viewport);
+ DrawLine(V(bounding_box.right, bounding_box.top, 0), V(bounding_box.right, bounding_box.bottom, 0), GRAY, viewport);
+ DrawLine(V(bounding_box.left, bounding_box.bottom, 0), V(bounding_box.right, bounding_box.bottom, 0), GRAY, viewport);
+ DrawLine(V(bounding_box.left, bounding_box.top, 0), V(bounding_box.left, bounding_box.bottom, 0), GRAY, viewport);
}
-// TODO: find a more efficient way to wireframe a mesh without duplicating edges
void WireframePolygon(int *polygon, Vertex *vertices, Viewport *viewport)
/* Rasterizes lines between each edge of a polygon */
{
@@ 59,31 89,31 @@ void WireframePolygon(int *polygon, Vertex *vertices, Viewport *viewport)
previous = LastPolygonVertex(polygon, vertices);
for (int i = 0; i < NumPolygonVertices(polygon); i++) {
current = PolygonVertex(polygon, vertices, i);
- RasterLine(*previous, *current, BLACK, viewport);
+ DrawLine(*previous, *current, BLACK, viewport);
previous = current;
}
}
-void RasterLine(Vertex a, Vertex b, Color color, Viewport *viewport)
+void DrawLine(Vertex a, Vertex b, Color color, Viewport *viewport)
{
double dx = b.x - a.x;
double dy = b.y - a.y;
if (fabs(dy) < fabs(dx)) {
if (a.x > b.x) {
- RasterLineShallow(b, a, color, viewport);
+ DrawLineShallow(b, a, color, viewport);
} else {
- RasterLineShallow(a, b, color, viewport);
+ DrawLineShallow(a, b, color, viewport);
}
} else {
if (a.y > b.y) {
- RasterLineSteep(b, a, color, viewport);
+ DrawLineSteep(b, a, color, viewport);
} else {
- RasterLineSteep(a, b, color, viewport);
+ DrawLineSteep(a, b, color, viewport);
}
}
}
-void RasterLineShallow(Vertex a, Vertex b, Color color, Viewport *viewport)
+void DrawLineShallow(Vertex a, Vertex b, Color color, Viewport *viewport)
{
double dx = b.x - a.x;
double dy = b.y - a.y;
@@ 110,7 140,7 @@ void RasterLineShallow(Vertex a, Vertex b, Color color, Viewport *viewport)
}
}
-void RasterLineSteep(Vertex a, Vertex b, Color color, Viewport *viewport)
+void DrawLineSteep(Vertex a, Vertex b, Color color, Viewport *viewport)
{
double dx = b.x - a.x;
double dy = b.y - a.y;
@@ 146,6 176,13 @@ void WritePixel(int x, int y, Color color, Viewport *viewport)
}
}
+void TryWritePixel(int x, int y, double z, Color color, Viewport *viewport)
+{
+ if (UpdateDepthBuffer(x, y, z, viewport)) {
+ WritePixel(x, y, color, viewport);
+ }
+}
+
Color GetPixel(int x, int y, Viewport *viewport)
/* Reads a pixel from a viewport's frame buffer */
{
@@ 179,3 216,33 @@ void DrawPoint(Vertex p, Color color, Viewport *viewport)
WritePixel(p.x, p.y, color, viewport);
}
}
+
+Rect PolygonBounds(int *polygon, Vertex *vertices)
+{
+ Rect r = { floor(vertices[0].x), floor(vertices[0].y), floor(vertices[0].x), floor(vertices[0].y) };
+ for (int i = 0; i < *polygon; i++) {
+ Vertex v = vertices[polygon[i+1]];
+ if (v.x < r.left) r.left = floor(v.x);
+ if (v.x > r.right) r.right = floor(v.x);
+ if (v.y < r.bottom) r.bottom = floor(v.y);
+ if (v.y > r.top) r.top = floor(v.y);
+ }
+ return r;
+}
+
+void PrintRect(Rect r)
+{
+ printf("%3d, %3d┌───┐%3d, %3d\n", r.left, r.top, r.right, r.top);
+ printf(" │ │\n");
+ printf("%3d, %3d└───┘%3d, %3d\n", r.left, r.bottom, r.right, r.bottom);
+ fflush(stdout);
+}
+
+EdgeTracker TrackEdge(Vertex *a, Vertex *b, Vertex start)
+{
+ EdgeTracker et;
+ et.dx = b->x - a->x;
+ et.dy = b->y - a->y;
+ et.value = (start.x - a->x)*et.dy - (start.y - a->y)*et.dx;
+ return et;
+}
M src/viewport.h => src/viewport.h +22 -5
@@ 29,17 29,34 @@ typedef struct Viewport {
int height;
} Viewport;
+typedef struct Rect {
+ int left;
+ int bottom;
+ int right;
+ int top;
+} Rect;
+
+typedef struct EdgeTracker {
+ float dx;
+ float dy;
+ float value;
+} EdgeTracker;
+
Viewport *NewViewport(Pixel *pixels, Color background_color, int width, int height);
DepthVal *NewDepthBuffer(int width, int height);
void ClearScreen(Viewport *viewport);
-void RasterizePolygon(int *polygon, Vertex *vertices, Viewport *viewport);
+void DrawPolygon(int *polygon, Vertex *vertices, Color color, Viewport *viewport);
void DrawBoundingBox(Rect boundingBox, Viewport *viewport);
void WireframePolygon(int *polygon, Vertex *vertices, Viewport *viewport);
+void TryWritePixel(int x, int y, double z, Color color, Viewport *viewport);
void WritePixel(int x, int y, Color color, Viewport *viewport);
Color GetPixel(int x, int y, Viewport *viewport);
void WriteDepth(int x, int y, DepthVal value, Viewport *viewport);
-void RasterLineSteep(Vertex a, Vertex b, Color color, Viewport *viewport);
-void RasterLineShallow(Vertex a, Vertex b, Color color, Viewport *viewport);
-void RasterLine(Vertex a, Vertex b, Color color, Viewport *viewport);
+void DrawLineSteep(Vertex a, Vertex b, Color color, Viewport *viewport);
+void DrawLineShallow(Vertex a, Vertex b, Color color, Viewport *viewport);
+void DrawLine(Vertex a, Vertex b, Color color, Viewport *viewport);
bool UpdateDepthBuffer(int x, int y, double z, Viewport *viewport);
-void DrawPoint(Vertex p, Color color, Viewport *viewport);>
\ No newline at end of file
+void DrawPoint(Vertex p, Color color, Viewport *viewport);
+Rect PolygonBounds(int *polygon, Vertex *vertices);
+void PrintRect(Rect r);
+EdgeTracker TrackEdge(Vertex *a, Vertex *b, Vertex start);