/* * Copyright (c) 2007-2023 Julien Nadeau Carriere * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Three-dimensional voxel object. */ #include #include #include /* Create a new Voxel node. */ SG_Voxel * SG_VoxelNew(void *parent, const char *name) { SG_Voxel *vol; vol = Malloc(sizeof(SG_Voxel)); AG_ObjectInit(vol, &sgVoxelClass); if (name) { AG_ObjectSetNameS(vol, name); } else { OBJECT(vol)->flags |= AG_OBJECT_NAME_ONATTACH; } AG_ObjectAttach(parent, vol); return (vol); } static void Init(void *_Nonnull obj) { SG_Voxel *vol = obj; vol->map = NULL; vol->w = 0; vol->h = 0; vol->d = 0; } static void Reset(void *_Nonnull obj) { SG_Voxel *vol = obj; int x, y; for (x = 0; x < vol->w; x++) { for (y = 0; y < vol->h; y++) { Free(vol->map[y]); } Free(vol->map[x]); } Free(vol->map); vol->map = NULL; vol->w = 0; vol->h = 0; vol->d = 0; } /* Set voxel dimensions in # of cells. */ void SG_VoxelAlloc3(SG_Voxel *vol, Uint w, Uint h, Uint d) { Uint x, y, z; AG_ObjectLock(vol); if (vol->map != NULL) { Reset(vol); } vol->w = w; vol->h = h; vol->d = d; vol->map = Malloc(w*sizeof(M_Real *)); for (x = 0; x < w; x++) { vol->map[x] = Malloc(h*sizeof(M_Real *)); for (y = 0; y < h; y++) { vol->map[x][y] = Malloc(d*sizeof(M_Real)); for (z = 0; z < d; z++) vol->map[x][y][z] = 0.0; } } AG_ObjectUnlock(vol); } /* Set the value of the cell at x,y,z to v. */ int SG_VoxelSet3(SG_Voxel *vol, int x, int y, int z, M_Real v) { AG_ObjectLock(vol); if (x < 0 || y < 0 || z < 0 || x >= (int)vol->w || y >= (int)vol->h || z >= (int)vol->d) { AG_SetError("No such cell: %d,%d,%d", x, y, z); goto fail; } vol->map[x][y][z] = v; AG_ObjectUnlock(vol); return (0); fail: AG_ObjectUnlock(vol); return (-1); } /* Set the value of all cells to v. */ void SG_VoxelReset(SG_Voxel *vol, M_Real v) { int x, y, z; AG_ObjectLock(vol); for (x = 0; x < vol->w; x++) { for (y = 0; y < vol->h; y++) { for (z = 0; z < vol->d; z++) vol->map[x][y][z] = v; } } AG_ObjectUnlock(vol); } static void Draw(void *_Nonnull obj, SG_View *_Nonnull sgv) { SG_Voxel *vol = obj; M_Color white = M_ColorWhite(); M_Vector3 p[8]; int x, y, z; p[0] = M_VECTOR3(0.0, 0.0, 0.0); p[1] = M_VECTOR3(1.0, 0.0, 0.0); p[2] = M_VECTOR3(1.0, 0.0, 1.0); p[3] = M_VECTOR3(0.0, 0.0, 1.0); p[4] = M_VECTOR3(0.0, 1.0, 0.0); p[5] = M_VECTOR3(1.0, 1.0, 0.0); p[6] = M_VECTOR3(1.0, 1.0, 1.0); p[7] = M_VECTOR3(0.0, 1.0, 1.0); GL_PushMatrix(); GL_PushAttrib(GL_LIGHTING_BIT); GL_Disable(GL_LIGHTING); GL_Scale3(vol->w, vol->h, vol->d); GL_Begin(GL_LINE_STRIP); { GL_Color3v(&white); GL_Vertex3v(&p[0]); GL_Vertex3v(&p[1]); GL_Vertex3v(&p[2]); GL_Vertex3v(&p[3]); GL_Vertex3v(&p[0]); GL_Vertex3v(&p[4]); GL_Vertex3v(&p[5]); GL_Vertex3v(&p[6]); GL_Vertex3v(&p[7]); GL_Vertex3v(&p[4]); } GL_End(); GL_Begin(GL_LINES); { GL_Color3v(&white); GL_Vertex3v(&p[1]); GL_Vertex3v(&p[5]); GL_Vertex3v(&p[2]); GL_Vertex3v(&p[6]); GL_Vertex3v(&p[3]); GL_Vertex3v(&p[7]); } GL_End(); GL_PopAttrib(); GL_PopMatrix(); for (x = 0; x < vol->w; x++) { for (y = 0; y < vol->h; y++) { for (z = 0; z < vol->d; z++) { M_Color C; M_Real cell; cell = vol->map[x][y][z]; if (cell == 0.0) { continue; } GL_PushMatrix(); GL_Translate(M_VECTOR3(x,y,z)); C = M_ColorRGB(0.0, cell, 0.0); GL_Begin(GL_QUADS); GL_MaterialColorv(GL_FRONT, GL_AMBIENT, &C); GL_MaterialColorv(GL_FRONT, GL_DIFFUSE, &C); GL_MaterialColorv(GL_FRONT, GL_SPECULAR, &C); GL_Normal3(0.0, -1.0, 0.0); /* TOP */ GL_Vertex3v(&p[7]); GL_Vertex3v(&p[6]); GL_Vertex3v(&p[5]); GL_Vertex3v(&p[4]); GL_Normal3(0.0, -1.0, 0.0); /* BOTTOM */ GL_Vertex3v(&p[1]); GL_Vertex3v(&p[2]); GL_Vertex3v(&p[3]); GL_Vertex3v(&p[0]); GL_Normal3(0.0, 0.0, -1.0); /* FRONT */ GL_Vertex3v(&p[4]); GL_Vertex3v(&p[5]); GL_Vertex3v(&p[1]); GL_Vertex3v(&p[0]); GL_Normal3(0.0, 0.0, -1.0); /* BACK */ GL_Vertex3v(&p[3]); GL_Vertex3v(&p[2]); GL_Vertex3v(&p[6]); GL_Vertex3v(&p[7]); GL_Normal3(-1.0, 0.0, 0.0); /* LEFT */ GL_Vertex3v(&p[3]); GL_Vertex3v(&p[7]); GL_Vertex3v(&p[4]); GL_Vertex3v(&p[0]); GL_Normal3(-1.0, 0.0, 0.0); /* RIGHT */ GL_Vertex3v(&p[5]); GL_Vertex3v(&p[6]); GL_Vertex3v(&p[2]); GL_Vertex3v(&p[1]); GL_End(); GL_PopMatrix(); } } } } SG_NodeClass sgVoxelClass = { { "SG_Node:SG_Voxel", sizeof(SG_Voxel), { 1,0, AGC_SG_VOXEL, 0xE01D }, Init, Reset, NULL, /* destroy */ NULL, /* load */ NULL, /* save */ SG_NodeEdit }, NULL, /* menuInstance */ NULL, /* menuClass */ Draw, NULL, /* intersect */ NULL /* edit */ };