commit a27e8a2912c7ca968ef7db342f3e387a561a9d02
parent 07cb54873a82a023c14edbd94f7221f6c6f6e181
Author: Brian Swetland <swetland@frotz.net>
Date: Tue, 15 Jan 2013 23:03:10 -0800
add some code to generate and render signed distance field textures
Diffstat:
6 files changed, 252 insertions(+), 5 deletions(-)
diff --git a/Makefile b/Makefile
@@ -10,22 +10,26 @@ LIBS := $(SDLLIBS) -lGL -lm -lpng
COMMONOBJS := util.o sdlglue.o loadpng.o loadfile.o loadobj.o
-all: test1 test2 test3
+all: test1 test2 test3 test4 mksdf
-TEST1OBJS := test1.o $(COMMONOBJS)
+mksdf: mksdf.c loadpng.c
+ gcc -g -Wall -o mksdf mksdf.c loadpng.c -lm -lpng
+TEST1OBJS := test1.o $(COMMONOBJS)
test1: $(TEST1OBJS)
$(CC) -o test1 $(TEST1OBJS) $(LIBS)
TEST2OBJS := test2.o $(COMMONOBJS)
-
test2: $(TEST2OBJS)
$(CC) -o test2 $(TEST2OBJS) $(LIBS)
TEST3OBJS := test3.o $(COMMONOBJS)
-
test3: $(TEST3OBJS)
$(CC) -o test3 $(TEST3OBJS) $(LIBS)
+TEST4OBJS := test4.o $(COMMONOBJS)
+test4: $(TEST4OBJS)
+ $(CC) -o test4 $(TEST4OBJS) $(LIBS)
+
clean::
- rm -f test1 test2 test3 *.o
+ rm -f test1 test2 test3 test4 mksdf *.o
diff --git a/mksdf.c b/mksdf.c
@@ -0,0 +1,109 @@
+/* Copyright 2013 Brian Swetland <swetland@frotz.net>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <math.h>
+
+#include "util.h"
+
+unsigned char *tex;
+unsigned tw, th;
+
+unsigned sample(int x, int y) {
+ if (x < 0) x = 0;
+ if (x >= tw) x = tw-1;
+ if (y < 0) y = 0;
+ if (y > th) y = th-1;
+ return tex[x + y * tw] >> 7;
+}
+
+/* this is absurdly brute-force and clunky */
+unsigned distance(int cx, int cy, int d) {
+ int x, y;
+ float dn = d*d+1.0, t;
+ unsigned cs = sample(cx, cy);
+ unsigned r;
+
+ for (y = cy - d; y <= cy + d; y++) {
+ for (x = cx - d; x <= cx + d; x++) {
+ if (sample(x, y) != cs) {
+ t = (cx-x)*(cx-x)+(cy-y)*(cy-y);
+ if (t < dn) dn = t;
+ }
+ }
+ }
+
+ dn = sqrt(dn);
+ r = ((127.0 * dn) / ((float) d));
+ if (r > 127) r = 127;
+ if (cs)
+ return 127 - r;
+ else
+ return 127 + r;
+}
+
+/* for each texel in the output texture, find the distance from its
+ * corresponding texel in the input texture to the nearest pixel of
+ * the opposite color
+ */
+void generate(unsigned char *map, int mw, int mh, int d) {
+ int x, y;
+ int up = tw / mw;
+ int dn = up / 2;
+ for (y = 0; y < mh; y++)
+ for (x = 0; x < mh; x++)
+ map[y*mw+x] = distance(x * up + dn, y * up + dn, d);
+}
+
+int main(int argc, char **argv) {
+ unsigned char *map;
+ unsigned mw, mh;
+ int x, y;
+
+ if (argc < 2) {
+ fprintf(stderr,"usage: mksdf <pngfile> [ <size> ]\n");
+ return -1;
+ } else if (argc < 3) {
+ mw = mh = 64;
+ } else {
+ mw = mh = atoi(argv[2]);
+ }
+ if (!(map = malloc(mw * mh))) {
+ fprintf(stderr,"out of memory\n");
+ return -1;
+ }
+
+ tex = load_png_gray(argv[1], &tw, &th);
+ if (!tex) {
+ fprintf(stderr,"cannot load source image '%s'\n", argv[1]);
+ return -1;
+ }
+
+ generate(map, mw, mh, tw / mw);
+
+ /* output an ascii PGM for now */
+ printf("P2\n%d %d\n255\n", mw, mh);
+ for (y = mh - 1; y >= 0; y--) {
+ for (x = 0; x < mw; x++)
+ printf("%d ", map[y*mw + x]);
+ printf("\n");
+ }
+ printf("\n");
+
+ return 0;
+}
+
diff --git a/test4.c b/test4.c
@@ -0,0 +1,113 @@
+/* Copyright 2013 Brian Swetland <swetland@frotz.net>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "util.h"
+#include "glue.h"
+
+void *texdata;
+unsigned texw, texh;
+
+const char *vert_src, *frag_src;
+
+GLuint pgm, vshd, fshd, tex0;
+GLuint _vPosition, _vUV;
+GLuint _uMVP, _uSampler;
+
+mat4 MVP;
+
+GLfloat verts[] = {
+ -1, -1, 0,
+ -1, 1, 0,
+ 1, -1, 0,
+ 1, 1, 0,
+ -0.5f, -0.5f, 0.0f,
+ -0.5f, 0.5f, 0.0f,
+ 0.5f, -0.5f, 0.0f,
+ 0.5f, 0.5f, 0.0f,
+};
+
+GLfloat texcoords[] = {
+ 0.0, 0.0,
+ 0.0, 1.0,
+ 1.0, 0.0,
+ 1.0, 1.0,
+};
+
+int scene_init(struct ctxt *c) {
+ if (!(texdata = load_png_gray("texture.sdf.png", &texw, &texh)))
+ return -1;
+ if (!(vert_src = load_file("test4.vertex.glsl", 0)))
+ return -1;
+ if (!(frag_src = load_file("test4.fragment.glsl", 0)))
+ return -1;
+
+ mtx_identity(MVP);
+ mtx_ortho(MVP, -1.333, 1.333, -1, 1, 1, -1);
+
+ glViewport(0, 0, c->width, c->height);
+ glClearColor(0, 0, 0, 0);
+ glClearDepth(1.0f);
+
+ if (shader_compile(vert_src, frag_src, &pgm, &vshd, &fshd))
+ return -1;
+
+ _vPosition = glGetAttribLocation(pgm, "vPosition");
+ _vUV = glGetAttribLocation(pgm, "vUV");
+ _uMVP = glGetUniformLocation(pgm, "uMVP");
+ _uSampler = glGetUniformLocation(pgm, "uSampler");
+
+ if(glGetError() != GL_NO_ERROR) fprintf(stderr,"OOPS!\n");
+
+ glEnable(GL_TEXTURE_2D);
+// glEnable(GL_BLEND);
+// glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+
+ glGenTextures(1, &tex0);
+
+ glBindTexture(GL_TEXTURE_2D, tex0);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, texw, texh, 0, GL_ALPHA,
+ GL_UNSIGNED_BYTE, texdata);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ return 0;
+}
+
+int scene_draw(struct ctxt *c) {
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ glLoadIdentity();
+ glUseProgram(pgm);
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, tex0);
+
+ glUniformMatrix4fv(_uMVP, 1, GL_FALSE, (void*) MVP);
+ glUniform1i(_uSampler, 0);
+
+ glVertexAttribPointer(_vPosition, 3, GL_FLOAT, GL_FALSE, 0, verts);
+ glEnableVertexAttribArray(_vPosition);
+
+ glVertexAttribPointer(_vUV, 2, GL_FLOAT, GL_FALSE, 0, texcoords);
+ glEnableVertexAttribArray(_vUV);
+
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+
+ return 0;
+}
+
diff --git a/test4.fragment.glsl b/test4.fragment.glsl
@@ -0,0 +1,11 @@
+uniform sampler2D uSampler;
+varying vec2 fUV;
+
+void main() {
+ float mask = texture2D(uSampler, fUV).a;
+
+ if (mask < 0.5)
+ discard;
+
+ gl_FragColor = vec4(1, 1, 0, 1);
+}
diff --git a/test4.vertex.glsl b/test4.vertex.glsl
@@ -0,0 +1,10 @@
+uniform mat4 uMVP;
+attribute vec4 vPosition;
+attribute vec2 vUV;
+varying vec2 fUV;
+
+void main() {
+ gl_Position = uMVP * vPosition;
+ fUV = vUV;
+}
+
diff --git a/texture.sdf.png b/texture.sdf.png
Binary files differ.