parg_mesh* parg_mesh_aar(parg_aar rect) { parg_mesh* surf = malloc(sizeof(struct parg_mesh_s)); surf->normals = 0; surf->indices = 0; surf->ntriangles = 2; int vertexCount = 4; int vertexStride = sizeof(float) * 2; surf->coords = parg_buffer_alloc(vertexCount * vertexStride, PARG_GPU_ARRAY); float* position = (float*) parg_buffer_lock(surf->coords, PARG_WRITE); *position++ = rect.left; *position++ = rect.bottom; *position++ = rect.right; *position++ = rect.bottom; *position++ = rect.left; *position++ = rect.top; *position++ = rect.right; *position = rect.top; parg_buffer_unlock(surf->coords); surf->uvs = parg_buffer_alloc(vertexCount * vertexStride, PARG_GPU_ARRAY); float* texcoord = (float*) parg_buffer_lock(surf->uvs, PARG_WRITE); *texcoord++ = 0; *texcoord++ = 0; *texcoord++ = 1; *texcoord++ = 0; *texcoord++ = 0; *texcoord++ = 1; *texcoord++ = 1; *texcoord = 1; parg_buffer_unlock(surf->uvs); return surf; }
parg_mesh* parg_mesh_from_shape(struct par_shapes_mesh_s const* src) { parg_mesh* dst = calloc(sizeof(struct parg_mesh_s), 1); dst->coords = parg_buffer_alloc(4 * 3 * src->npoints, PARG_GPU_ARRAY); float* pcoords = (float*) parg_buffer_lock(dst->coords, PARG_WRITE); memcpy(pcoords, src->points, 4 * 3 * src->npoints); parg_buffer_unlock(dst->coords); if (src->tcoords) { dst->uvs = parg_buffer_alloc(4 * 2 * src->npoints, PARG_GPU_ARRAY); float* puvs = (float*) parg_buffer_lock(dst->uvs, PARG_WRITE); memcpy(puvs, src->tcoords, 4 * 2 * src->npoints); parg_buffer_unlock(dst->uvs); } if (src->normals) { dst->normals = parg_buffer_alloc(4 * 3 * src->npoints, PARG_GPU_ARRAY); float* pnorms = (float*) parg_buffer_lock(dst->normals, PARG_WRITE); memcpy(pnorms, src->normals, 4 * 3 * src->npoints); parg_buffer_unlock(dst->normals); } dst->indices = parg_buffer_alloc(2 * 3 * src->ntriangles, PARG_GPU_ELEMENTS); uint16_t* ptris = (uint16_t*) parg_buffer_lock(dst->indices, PARG_WRITE); memcpy(ptris, src->triangles, 2 * 3 * src->ntriangles); parg_buffer_unlock(dst->indices); dst->ntriangles = src->ntriangles; return dst; }
parg_mesh* parg_mesh_knot(int slices, int stacks, float major, float minor) { parg_mesh* surf = malloc(sizeof(struct parg_mesh_s)); float ds = 1.0f / slices; float dt = 1.0f / stacks; int vertexCount = slices * stacks * 3; int vertexStride = sizeof(float) * 3; surf->coords = parg_buffer_alloc(vertexCount * vertexStride, PARG_GPU_ARRAY); surf->normals = parg_buffer_alloc(vertexCount * vertexStride, PARG_GPU_ARRAY); surf->uvs = 0; Point3* position = (Point3*) parg_buffer_lock(surf->coords, PARG_WRITE); Vector3* normal = (Vector3*) parg_buffer_lock(surf->normals, PARG_WRITE); for (float s = 0; s < 1 - ds / 2; s += ds) { for (float t = 0; t < 1 - dt / 2; t += dt) { const float E = 0.01f; Point3 p = knot_fn(s, t); Vector3 u = P3Sub(knot_fn(s + E, t), p); Vector3 v = P3Sub(knot_fn(s, t + E), p); Vector3 n = V3Normalize(V3Cross(u, v)); *position++ = p; *normal++ = n; } } parg_buffer_unlock(surf->coords); parg_buffer_unlock(surf->normals); surf->ntriangles = slices * stacks * 2; int indexCount = surf->ntriangles * 3; surf->indices = parg_buffer_alloc(indexCount * 2, PARG_GPU_ELEMENTS); uint16_t* index = (uint16_t*) parg_buffer_lock(surf->indices, PARG_WRITE); int v = 0; for (int i = 0; i < slices - 1; i++) { for (int j = 0; j < stacks; j++) { int next = (j + 1) % stacks; *index++ = v + next + stacks; *index++ = v + next; *index++ = v + j; *index++ = v + j; *index++ = v + j + stacks; *index++ = v + next + stacks; } v += stacks; } for (int j = 0; j < stacks; j++) { int next = (j + 1) % stacks; *index++ = next; *index++ = v + next; *index++ = v + j; *index++ = v + j; *index++ = j; *index++ = next; } parg_buffer_unlock(surf->indices); return surf; }
parg_buffer* parg_buffer_dup(parg_buffer* srcbuf, parg_buffer_type memtype) { int nbytes = parg_buffer_length(srcbuf); parg_buffer* dstbuf = parg_buffer_alloc(nbytes, memtype); void* src = parg_buffer_lock(srcbuf, PARG_READ); void* dst = parg_buffer_lock(dstbuf, PARG_WRITE); memcpy(dst, src, nbytes); parg_buffer_unlock(dstbuf); parg_buffer_unlock(srcbuf); return dstbuf; }
void parg_mesh_compute_normals(parg_mesh* mesh) { par_shapes_mesh m = {0}; int nbytes = parg_buffer_length(mesh->coords); m.points = (float*) parg_buffer_lock(mesh->coords, PARG_READ); m.triangles = (uint16_t*) parg_buffer_lock(mesh->indices, PARG_READ); m.npoints = nbytes / 12; m.ntriangles = mesh->ntriangles; par_shapes_compute_normals(&m); mesh->normals = parg_buffer_create(m.normals, nbytes, PARG_CPU); parg_buffer_unlock(mesh->coords); parg_buffer_unlock(mesh->indices); free(m.normals); }
void parg_mesh_update_from_shape(parg_mesh* dst, struct par_shapes_mesh_s const* src) { float* pcoords = (float*) parg_buffer_lock(dst->coords, PARG_WRITE); memcpy(pcoords, src->points, 4 * 3 * src->npoints); parg_buffer_unlock(dst->coords); }
void init(float winwidth, float winheight, float pixratio) { const Vector4 bgcolor = {0.937, 0.937, 0.93, 1.00}; parg_state_clearcolor(bgcolor); parg_state_cullfaces(1); parg_state_depthtest(1); parg_shader_load_from_asset(SHADER_SIMPLE); int* rawdata; colorbuf = parg_buffer_slurp_asset(TEXTURE_COLOR, (void*) &rawdata); int width = *rawdata++; int height = *rawdata++; int ncomps = *rawdata++; parg_buffer_unlock(colorbuf); colortex = parg_texture_from_u8(colorbuf, width, height, ncomps, 3 * sizeof(int)); graybuf = parg_buffer_from_asset(BIN_ISLAND); graytex = parg_texture_from_fp32(graybuf, IMGWIDTH, IMGHEIGHT, 1, 0); const float h = 1.5f; const float w = h * winwidth / winheight; const float znear = 10; const float zfar = 90; projection = M4MakeFrustum(-w, w, -h, h, znear, zfar); Point3 eye = {0, -50, 50}; Point3 target = {0, 0, 0}; Vector3 up = {0, 1, 0}; view = M4MakeLookAt(eye, target, up); rectmesh = parg_mesh_rectangle(20, 20); }
parg_buffer* parg_buffer_to_gpu(parg_buffer* cpubuf, parg_buffer_type memtype) { int nbytes = parg_buffer_length(cpubuf); void* bytes = parg_buffer_lock(cpubuf, PARG_READ); parg_buffer* gpubuf = parg_buffer_create(bytes, nbytes, memtype); parg_buffer_unlock(cpubuf); return gpubuf; }
void parg_buffer_to_file(parg_buffer* buf, const char* filepath) { FILE* f = fopen(filepath, "wb"); parg_verify(f, "Unable to open file", filepath); char* contents = parg_buffer_lock(buf, PARG_READ); fwrite(contents, 1, parg_buffer_length(buf), f); fclose(f); parg_buffer_unlock(buf); }
parg_buffer* parg_buffer_from_file(const char* filepath) { FILE* f = fopen(filepath, "rb"); parg_verify(f, "Unable to open file", filepath); fseek(f, 0, SEEK_END); long fsize = ftell(f); fseek(f, 0, SEEK_SET); parg_buffer* retval = parg_buffer_alloc(fsize + 1, PARG_CPU); char* contents = parg_buffer_lock(retval, PARG_WRITE); fread(contents, fsize, 1, f); fclose(f); contents[fsize] = 0; parg_buffer_unlock(retval); return retval; }
void init(float winwidth, float winheight, float pixratio) { printf( "Spacebar to toggle texture modes.\n" "D to toggle auto-zooming demo mode.\n" "G to toggle the slippy map grid.\n"); parg_state_clearcolor((Vector4){0.43, 0.61, 0.8, 1}); parg_state_cullfaces(1); parg_state_depthtest(0); parg_shader_load_from_asset(SHADER_DEFAULT); parg_zcam_init(1, 1, fovy); parg_zcam_set_position(0, 0, STARTZ); ocean_texture = parg_texture_from_asset(TEXTURE_OCEAN); paper_texture = parg_texture_from_asset(TEXTURE_PAPER); // Decode the europe image. int* rawdata; parg_buffer* colorbuf = parg_buffer_slurp_asset(TEXTURE_EUROPE, (void*) &rawdata); int width = *rawdata++; int height = *rawdata++; int ncomps = *rawdata++; parg_texture_fliprows(rawdata, width * ncomps, height); // Sample the ocean color from one corner of the image. int ocean_color = rawdata[0]; // Perform marching squares and generate a mesh. par_msquares_meshlist* mlist = par_msquares_color((parg_byte*) rawdata, width, height, 16, ocean_color, 4, PAR_MSQUARES_SWIZZLE | PAR_MSQUARES_DUAL | PAR_MSQUARES_HEIGHTS | PAR_MSQUARES_SIMPLIFY); par_msquares_mesh const* mesh; mesh = par_msquares_get_mesh(mlist, 0); landmass_mesh = parg_mesh_create( mesh->points, mesh->npoints, mesh->triangles, mesh->ntriangles); mesh = par_msquares_get_mesh(mlist, 1); ocean_mesh = parg_mesh_create( mesh->points, mesh->npoints, mesh->triangles, mesh->ntriangles); parg_buffer_unlock(colorbuf); par_msquares_free(mlist); }
void parg_asset_preload(parg_token id) { if (!_pngsuffix) { _pngsuffix = sdsnew(".png"); } sds filename = parg_token_to_sds(id); parg_buffer* buf = parg_buffer_from_path(filename); parg_assert(buf, "Unable to load asset"); if (sdslen(filename) > 4) { sds suffix = sdsdup(filename); sdsrange(suffix, -4, -1); if (!sdscmp(suffix, _pngsuffix)) { unsigned char* decoded; unsigned dims[3] = {0, 0, 4}; unsigned char* filedata = parg_buffer_lock(buf, PARG_READ); unsigned err = lodepng_decode_memory(&decoded, &dims[0], &dims[1], filedata, parg_buffer_length(buf), LCT_RGBA, 8); parg_assert(err == 0, "PNG decoding error"); parg_buffer_free(buf); int nbytes = dims[0] * dims[1] * dims[2]; buf = parg_buffer_alloc(nbytes + 12, PARG_CPU); int* ptr = parg_buffer_lock(buf, PARG_WRITE); *ptr++ = dims[0]; *ptr++ = dims[1]; *ptr++ = dims[2]; memcpy(ptr, decoded, nbytes); free(decoded); parg_buffer_unlock(buf); } sdsfree(suffix); } if (!_asset_registry) { _asset_registry = kh_init(assmap); } int ret; int iter = kh_put(assmap, _asset_registry, id, &ret); kh_value(_asset_registry, iter) = buf; }
parg_mesh* parg_mesh_sierpinski(float width, int depth) { parg_mesh* surf = malloc(sizeof(struct parg_mesh_s)); surf->normals = 0; surf->indices = 0; surf->uvs = 0; surf->ntriangles = pow(3, depth); int vstride = sizeof(float) * 2; int ntriangles = 1; int nverts = ntriangles * 3; float height = width * sqrt(0.75); parg_buffer* src = parg_buffer_alloc(nverts * vstride, PARG_CPU); float* psrc = (float*) parg_buffer_lock(src, PARG_WRITE); *psrc++ = 0; *psrc++ = height * 0.5; *psrc++ = width * 0.5; *psrc++ = -height * 0.5; *psrc++ = -width * 0.5; *psrc++ = -height * 0.5; parg_buffer_unlock(src); #define WRITE_TRIANGLE(a, b, c) \ *pdst++ = x[a]; \ *pdst++ = y[a]; \ *pdst++ = x[b]; \ *pdst++ = y[b]; \ *pdst++ = x[c]; \ *pdst++ = y[c] float x[6]; float y[6]; while (depth--) { ntriangles *= 3; nverts = ntriangles * 3; parg_buffer* dst = parg_buffer_alloc(nverts * vstride, PARG_CPU); float* pdst = parg_buffer_lock(dst, PARG_WRITE); const float* psrc = parg_buffer_lock(src, PARG_READ); for (int i = 0; i < ntriangles / 3; i++) { x[0] = *psrc++; y[0] = *psrc++; x[1] = *psrc++; y[1] = *psrc++; x[2] = *psrc++; y[2] = *psrc++; x[3] = 0.5 * (x[0] + x[1]); y[3] = 0.5 * (y[0] + y[1]); x[4] = 0.5 * (x[1] + x[2]); y[4] = 0.5 * (y[1] + y[2]); x[5] = 0.5 * (x[0] + x[2]); y[5] = 0.5 * (y[0] + y[2]); WRITE_TRIANGLE(0, 3, 5); WRITE_TRIANGLE(3, 1, 4); WRITE_TRIANGLE(5, 4, 2); } parg_buffer_unlock(src); parg_buffer_unlock(dst); parg_buffer_free(src); src = dst; } assert(surf->ntriangles == ntriangles); surf->coords = parg_buffer_alloc(nverts * vstride, PARG_GPU_ARRAY); float* pdst = parg_buffer_lock(surf->coords, PARG_WRITE); psrc = parg_buffer_lock(src, PARG_READ); memcpy(pdst, psrc, nverts * vstride); parg_buffer_unlock(src); parg_buffer_unlock(surf->coords); parg_buffer_free(src); return surf; }
parg_mesh* parg_mesh_torus(int slices, int stacks, float major, float minor) { parg_mesh* surf = malloc(sizeof(struct parg_mesh_s)); float dphi = PARG_TWOPI / stacks; float dtheta = PARG_TWOPI / slices; int vertexCount = slices * stacks * 3; int vertexStride = sizeof(float) * 3; surf->coords = parg_buffer_alloc(vertexCount * vertexStride, PARG_GPU_ARRAY); surf->uvs = 0; Point3* position = (Point3*) parg_buffer_lock(surf->coords, PARG_WRITE); for (int slice = 0; slice < slices; slice++) { float theta = slice * dtheta; for (int stack = 0; stack < stacks; stack++) { float phi = stack * dphi; *position++ = torus_fn(major, minor, phi, theta); } } parg_buffer_unlock(surf->coords); surf->normals = parg_buffer_alloc(vertexCount * vertexStride, PARG_GPU_ARRAY); Vector3* normal = (Vector3*) parg_buffer_lock(surf->normals, PARG_WRITE); for (int slice = 0; slice < slices; slice++) { float theta = slice * dtheta; for (int stack = 0; stack < stacks; stack++) { float phi = stack * dphi; Point3 p = torus_fn(major, minor, phi, theta); Point3 p1 = torus_fn(major, minor, phi, theta + 0.01); Point3 p2 = torus_fn(major, minor, phi + 0.01, theta); Vector3 du = P3Sub(p2, p); Vector3 dv = P3Sub(p1, p); *normal = V3Normalize(V3Cross(du, dv)); ++normal; } } parg_buffer_unlock(surf->normals); surf->ntriangles = slices * stacks * 2; int indexCount = surf->ntriangles * 3; surf->indices = parg_buffer_alloc(indexCount * 2, PARG_GPU_ELEMENTS); uint16_t* index = (uint16_t*) parg_buffer_lock(surf->indices, PARG_WRITE); int v = 0; for (int i = 0; i < slices - 1; i++) { for (int j = 0; j < stacks; j++) { int next = (j + 1) % stacks; *index++ = v + next + stacks; *index++ = v + next; *index++ = v + j; *index++ = v + j; *index++ = v + j + stacks; *index++ = v + next + stacks; } v += stacks; } for (int j = 0; j < stacks; j++) { int next = (j + 1) % stacks; *index++ = next; *index++ = v + next; *index++ = v + j; *index++ = v + j; *index++ = j; *index++ = next; } parg_buffer_unlock(surf->indices); return surf; }
static void create_mesh() { par_msquares_meshlist* mlist = 0; float threshold = 0; int flags = 0; if (state == STATE_GRAY_DEFAULT) { float const* graydata = parg_buffer_lock(graybuf, PARG_READ); mlist = par_msquares_grayscale( graydata, IMGWIDTH, IMGHEIGHT, CELLSIZE, threshold, flags); parg_buffer_unlock(graybuf); } else if (state == STATE_GRAY_SIMPLIFY) { float const* graydata = parg_buffer_lock(graybuf, PARG_READ); flags = PAR_MSQUARES_SIMPLIFY; mlist = par_msquares_grayscale( graydata, IMGWIDTH, IMGHEIGHT, CELLSIZE, threshold, flags); parg_buffer_unlock(graybuf); } else if (state == STATE_GRAY_INVERT) { float const* graydata = parg_buffer_lock(graybuf, PARG_READ); flags = PAR_MSQUARES_INVERT; mlist = par_msquares_grayscale( graydata, IMGWIDTH, IMGHEIGHT, CELLSIZE, threshold, flags); parg_buffer_unlock(graybuf); } else if (state == STATE_GRAY_DUAL) { float const* graydata = parg_buffer_lock(graybuf, PARG_READ); flags = PAR_MSQUARES_DUAL; mlist = par_msquares_grayscale( graydata, IMGWIDTH, IMGHEIGHT, CELLSIZE, threshold, flags); parg_buffer_unlock(graybuf); } else if (state == STATE_GRAY_HEIGHTS) { float const* graydata = parg_buffer_lock(graybuf, PARG_READ); flags = PAR_MSQUARES_HEIGHTS; mlist = par_msquares_grayscale( graydata, IMGWIDTH, IMGHEIGHT, CELLSIZE, threshold, flags); parg_buffer_unlock(graybuf); } else if (state == STATE_GRAY_DHS) { float const* graydata = parg_buffer_lock(graybuf, PARG_READ); flags = PAR_MSQUARES_DUAL | PAR_MSQUARES_HEIGHTS | PAR_MSQUARES_SNAP; mlist = par_msquares_grayscale( graydata, IMGWIDTH, IMGHEIGHT, CELLSIZE, threshold, flags); parg_buffer_unlock(graybuf); } else if (state == STATE_GRAY_DHSC) { float const* graydata = parg_buffer_lock(graybuf, PARG_READ); flags = PAR_MSQUARES_DUAL | PAR_MSQUARES_HEIGHTS | PAR_MSQUARES_SNAP | PAR_MSQUARES_CONNECT; mlist = par_msquares_grayscale( graydata, IMGWIDTH, IMGHEIGHT, CELLSIZE, threshold, flags); parg_buffer_unlock(graybuf); } else if (state == STATE_GRAY_MULTI) { float const* graydata = parg_buffer_lock(graybuf, PARG_READ); float thresholds[] = {0.0, 0.1}; flags = PAR_MSQUARES_SIMPLIFY | PAR_MSQUARES_HEIGHTS | PAR_MSQUARES_SNAP | PAR_MSQUARES_CONNECT; mlist = par_msquares_grayscale_multi( graydata, IMGWIDTH, IMGHEIGHT, CELLSIZE, thresholds, 2, flags); parg_buffer_unlock(graybuf); } else if (state == STATE_COLOR_DEFAULT) { parg_byte const* rgbadata = parg_buffer_lock(colorbuf, PARG_READ); rgbadata += sizeof(int) * 3; mlist = par_msquares_color( rgbadata, IMGWIDTH, IMGHEIGHT, CELLSIZE, 0x214562, 4, flags); parg_buffer_unlock(colorbuf); } else if (state == STATE_COLOR_IH) { parg_byte const* rgbadata = parg_buffer_lock(colorbuf, PARG_READ); rgbadata += sizeof(int) * 3; flags = PAR_MSQUARES_INVERT | PAR_MSQUARES_HEIGHTS; mlist = par_msquares_color( rgbadata, IMGWIDTH, IMGHEIGHT, CELLSIZE, 0x214562, 4, flags); parg_buffer_unlock(colorbuf); } else if (state == STATE_COLOR_DHSCSI) { parg_byte const* rgbadata = parg_buffer_lock(colorbuf, PARG_READ); rgbadata += sizeof(int) * 3; flags = PAR_MSQUARES_DUAL | PAR_MSQUARES_HEIGHTS | PAR_MSQUARES_SNAP | PAR_MSQUARES_CONNECT | PAR_MSQUARES_SIMPLIFY | PAR_MSQUARES_INVERT; mlist = par_msquares_color( rgbadata, IMGWIDTH, IMGHEIGHT, CELLSIZE, 0x214562, 4, flags); parg_buffer_unlock(colorbuf); } else if (state == STATE_MULTI_RGB) { unsigned dims[2] = {0, 0}; unsigned char* pixels; lodepng_decode_file( &pixels, &dims[0], &dims[1], "extern/par/test/rgb.png", LCT_RGB, 8); mlist = par_msquares_color_multi( pixels, dims[0], dims[1], 16, 3, PAR_MSQUARES_SIMPLIFY); free(pixels); } else if (state == STATE_MULTI_RGBA) { unsigned dims[2] = {0, 0}; unsigned char* pixels; lodepng_decode_file(&pixels, &dims[0], &dims[1], "extern/par/test/rgba.png", LCT_RGBA, 8); mlist = par_msquares_color_multi(pixels, dims[0], dims[1], 16, 4, PAR_MSQUARES_HEIGHTS | PAR_MSQUARES_CONNECT | PAR_MSQUARES_SIMPLIFY); free(pixels); } else if (state == STATE_MULTI_DIAGRAM) { parg_byte const* rgbadata = parg_buffer_lock(colorbuf, PARG_READ); rgbadata += sizeof(int) * 3; mlist = par_msquares_color_multi(rgbadata, IMGWIDTH, IMGHEIGHT, CELLSIZE, 4, PAR_MSQUARES_SIMPLIFY | PAR_MSQUARES_HEIGHTS); parg_buffer_unlock(colorbuf); } nmeshes = par_msquares_get_count(mlist); printf("%d meshes\n", nmeshes); for (int imesh = 0; imesh < nmeshes; imesh++) { par_msquares_mesh const* mesh = par_msquares_get_mesh(mlist, imesh); // mquares_mesh might have dimensionality of 2 or 3, while parg_mesh // only // supports the latter. So, we potentially need to expand the data from // vec2 to vec3. float* points = mesh->points; if (mesh->dim == 2) { points = malloc(mesh->npoints * sizeof(float) * 3); for (int i = 0; i < mesh->npoints; i++) { points[i * 3] = mesh->points[i * 2]; points[i * 3 + 1] = mesh->points[i * 2 + 1]; points[i * 3 + 2] = 0; } } meshcolors[imesh] = mesh->color; trimesh[imesh] = parg_mesh_create( points, mesh->npoints, mesh->triangles, mesh->ntriangles); if (mesh->dim == 2) { free(points); } } par_msquares_free(mlist); }