static void
edge_lines_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObject *mask_light) {
    PrimitiveEdgeLines *self = (PrimitiveEdgeLines *)data;

    /* Draw some edge lines! */
    if (state->block == 44 || state->block == 78 || !is_transparent(state->block)) {
        Imaging img_i = imaging_python_to_c(state->img);
        unsigned char ink[] = {0, 0, 0, 255 * self->opacity};
        unsigned short side_block;
        int x = state->x, y = state->y, z = state->z;

        int increment=0;
        if (state->block == 44 && ((state->block_data & 0x8) == 0 ))  // half-step BUT no upsidown half-step
            increment=6;
        else if ((state->block == 78) || (state->block == 93) || (state->block == 94)) // snow, redstone repeaters (on and off)
            increment=9;
        
        /* +X side */
        side_block = get_data(state, BLOCKS, x+1, y, z);
        if (side_block != state->block && (is_transparent(side_block) || render_mode_hidden(state->rendermode, x+1, y, z))) {
            ImagingDrawLine(img_i, state->imgx+12, state->imgy+1+increment, state->imgx+22+1, state->imgy+5+1+increment, &ink, 1);
            ImagingDrawLine(img_i, state->imgx+12, state->imgy+increment, state->imgx+22+1, state->imgy+5+increment, &ink, 1);
        }
        
        /* -Z side */
        side_block = get_data(state, BLOCKS, x, y, z-1);
        if (side_block != state->block && (is_transparent(side_block) || render_mode_hidden(state->rendermode, x, y, z-1))) {
            ImagingDrawLine(img_i, state->imgx, state->imgy+6+1+increment, state->imgx+12+1, state->imgy+1+increment, &ink, 1);
            ImagingDrawLine(img_i, state->imgx, state->imgy+6+increment, state->imgx+12+1, state->imgy+increment, &ink, 1);
        }
    }
}
static int
rendermode_overlay_occluded(void *data, RenderState *state) {
    int x = state->x, y = state->y, z = state->z;
    
    if ( (x != 0) && (y != 15) && (z != 127) &&
         !is_transparent(getArrayByte3D(state->blocks, x-1, y, z)) &&
         !is_transparent(getArrayByte3D(state->blocks, x, y, z+1)) &&
         !is_transparent(getArrayByte3D(state->blocks, x, y+1, z))) {
        return 1;
    }
    
    return 0;
}
static int
rendermode_normal_occluded(void *data, RenderState *state, int x, int y, int z) {
    if ( (x != 0) && (y != 15) && (z != 127) &&
         !render_mode_hidden(state->rendermode, x-1, y, z) &&
         !render_mode_hidden(state->rendermode, x, y, z+1) &&
         !render_mode_hidden(state->rendermode, x, y+1, z) &&
         !is_transparent(getArrayByte3D(state->blocks, x-1, y, z)) &&
         !is_transparent(getArrayByte3D(state->blocks, x, y, z+1)) &&
         !is_transparent(getArrayByte3D(state->blocks, x, y+1, z))) {
        return 1;
    }

    return 0;
}
Example #4
0
void texture_info::set_coloralphamode(SDL_Texture *texture_id, const render_color *color)
{
	UINT32 sr = (UINT32)(255.0f * color->r);
	UINT32 sg = (UINT32)(255.0f * color->g);
	UINT32 sb = (UINT32)(255.0f * color->b);
	UINT32 sa = (UINT32)(255.0f * color->a);


	if (color->r >= 1.0f && color->g >= 1.0f && color->b >= 1.0f && is_opaque(color->a))
	{
		SDL_SetTextureColorMod(texture_id, 0xFF, 0xFF, 0xFF);
		SDL_SetTextureAlphaMod(texture_id, 0xFF);
	}
	/* coloring-only case */
	else if (is_opaque(color->a))
	{
		SDL_SetTextureColorMod(texture_id, sr, sg, sb);
		SDL_SetTextureAlphaMod(texture_id, 0xFF);
	}
	/* alpha and/or coloring case */
	else if (!is_transparent(color->a))
	{
		SDL_SetTextureColorMod(texture_id, sr, sg, sb);
		SDL_SetTextureAlphaMod(texture_id, sa);
	}
	else
	{
		SDL_SetTextureColorMod(texture_id, 0xFF, 0xFF, 0xFF);
		SDL_SetTextureAlphaMod(texture_id, 0x00);
	}
}
Example #5
0
static void
lighting_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObject *mask_light) {
    RenderPrimitiveLighting* self;
    int x, y, z;

    self = (RenderPrimitiveLighting *)data;
    x = state->x, y = state->y, z = state->z;
    
    if ((state->block == 9) || (state->block == 79)) { /* special case for water and ice */
        /* looks like we need a new case for lighting, there are
         * blocks that are transparent for occlusion calculations and
         * need per-face shading if the face is drawn. */
        if ((state->block_pdata & 16) == 16) {
            do_shading_with_mask(self, state, x, y+1, z, self->facemasks[0]);
        }
        if ((state->block_pdata & 2) == 2) { /* bottom left */
            do_shading_with_mask(self, state, x-1, y, z, self->facemasks[1]);
        }
        if ((state->block_pdata & 4) == 4) { /* bottom right */
            do_shading_with_mask(self, state, x, y, z+1, self->facemasks[2]);
        }
        /* leaves are transparent for occlusion calculations but they 
         * per face-shading to look as in game */
    } else if (is_transparent(state->block) && (state->block != 18)) {
        /* transparent: do shading on whole block */
        do_shading_with_mask(self, state, x, y, z, mask_light);
    } else {
        /* opaque: do per-face shading */
        do_shading_with_mask(self, state, x, y+1, z, self->facemasks[0]);
        do_shading_with_mask(self, state, x-1, y, z, self->facemasks[1]);
        do_shading_with_mask(self, state, x, y, z+1, self->facemasks[2]);
    }
}
Example #6
0
int to_system(Color color)
{
  if (is_transparent(color))
    return -1;
  else
    return makecol(getr(color),
                   getg(color),
                   getb(color));
}
static void
rendermode_overlay_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObject *mask_light) {
    RenderModeOverlay *self = (RenderModeOverlay *)data;
    unsigned char r, g, b, a;
    PyObject *top_block_py, *block_py;
    
    // exactly analogous to edge-line code for these special blocks
    int increment=0;
    if (state->block == 44)  // half-step
        increment=6;
    else if (state->block == 78) // snow
        increment=9;
    
    /* clear the draw space -- set alpha to 0 within mask */
    tint_with_mask(state->img, 255, 255, 255, 0, mask, state->imgx, state->imgy, 0, 0);

    /* skip rendering the overlay if we can't see it */
    if (state->z != 127) {
        unsigned char top_block = getArrayByte3D(state->blocks, state->x, state->y, state->z+1);
        if (!is_transparent(top_block)) {
            return;
        }
        
        /* check to be sure this block is solid/fluid */
        top_block_py = PyInt_FromLong(top_block);
        if (PySequence_Contains(self->solid_blocks, top_block_py) ||
            PySequence_Contains(self->fluid_blocks, top_block_py)) {
            
            /* top block is fluid or solid, skip drawing */
            Py_DECREF(top_block_py);
            return;
        }
        Py_DECREF(top_block_py);
    }
    
    /* check to be sure this block is solid/fluid */
    block_py = PyInt_FromLong(state->block);
    if (!PySequence_Contains(self->solid_blocks, block_py) &&
        !PySequence_Contains(self->fluid_blocks, block_py)) {
        
        /* not fluid or solid, skip drawing the overlay */
        Py_DECREF(block_py);
        return;
    }
    Py_DECREF(block_py);

    /* get our color info */
    self->get_color(data, state, &r, &g, &b, &a);
    
    /* do the overlay */
    if (a > 0) {
        alpha_over(state->img, self->white_color, self->facemask_top, state->imgx, state->imgy + increment, 0, 0);
        tint_with_mask(state->img, r, g, b, a, self->facemask_top, state->imgx, state->imgy + increment, 0, 0);
    }
}
Example #8
0
/* does per-face occlusion checking for do_shading_with_mask */
inline int
lighting_is_face_occluded(RenderState *state, int skip_sides, int x, int y, int z) {
    /* first, check for occlusion if the block is in the local chunk */
    if (x >= 0 && x < 16 && y >= 0 && y < 16 && z >= 0 && z < 16) {
        unsigned short block = getArrayShort3D(state->blocks, x, y, z);
        
        if (!is_transparent(block) && !render_mode_hidden(state->rendermode, x, y, z)) {
            /* this face isn't visible, so don't draw anything */
            return 1;
        }
    } else if (!skip_sides) {
        unsigned short block = get_data(state, BLOCKS, x, y, z);
        if (!is_transparent(block)) {
            /* the same thing but for adjacent chunks, this solves an
               ugly black doted line between chunks in night rendermode.
               This wouldn't be necessary if the textures were truly
               tessellate-able */
               return 1;
        }
    }
    return 0;
}
/* shades the drawn block with the given facemask/black_color, based on the
   lighting results from (x, y, z) */
static inline void
do_shading_with_mask(RenderModeLighting *self, RenderState *state,
                     int x, int y, int z, PyObject *mask) {
    float black_coeff;
    
    /* first, check for occlusion if the block is in the local chunk */
    if (x >= 0 && x < 16 && y >= 0 && y < 16 && z >= 0 && z < 128) {
        unsigned char block = getArrayByte3D(state->blocks, x, y, z);
        
        if (!is_transparent(block) && !render_mode_hidden(state->rendermode, x, y, z)) {
            /* this face isn't visible, so don't draw anything */
            return;
        }
    } else if (self->skip_sides && (x == -1) && (state->left_blocks != Py_None)) {
        unsigned char block = getArrayByte3D(state->left_blocks, 15, state->y, state->z);
        if (!is_transparent(block)) {
            /* the same thing but for adjacent chunks, this solves an
               ugly black doted line between chunks in night rendermode.
               This wouldn't be necessary if the textures were truly
               tessellate-able */
               return;
           }
    } else if (self->skip_sides && (y == 16) && (state->right_blocks != Py_None)) {
        unsigned char block = getArrayByte3D(state->right_blocks, state->x, 0, state->z);
        if (!is_transparent(block)) {
            /* the same thing but for adjacent chunks, this solves an
               ugly black doted line between chunks in night rendermode.
               This wouldn't be necessary if the textures were truly
               tessellate-able */
               return;
           }
    }
    
    black_coeff = get_lighting_coefficient(self, state, x, y, z);
    black_coeff *= self->shade_strength;
    alpha_over_full(state->img, self->black_color, mask, black_coeff, state->imgx, state->imgy, 0, 0);
}
Example #10
0
inline unsigned char
estimate_blocklevel(RenderPrimitiveLighting *self, RenderState *state,
                         int x, int y, int z, int *authoratative) {

    /* placeholders for later data arrays, coordinates */
    unsigned char block, blocklevel;
    unsigned int average_count = 0, average_gather = 0, coeff = 0;

    /* defaults to "guess" until told otherwise */
    if (authoratative)
        *authoratative = 0;
    
    block = get_data(state, BLOCKS, x, y, z);
    
    if (authoratative == NULL) {
        int auth;
        
        /* iterate through all surrounding blocks to take an average */
        int dx, dy, dz, local_block;
        for (dx = -1; dx <= 1; dx += 2) {
            for (dy = -1; dy <= 1; dy += 2) {
                for (dz = -1; dz <= 1; dz += 2) {
                    coeff = estimate_blocklevel(self, state, x+dx, y+dy, z+dz, &auth);
                    local_block = get_data(state, BLOCKS, x+dx, y+dy, z+dz);
                    /* only add if the block is transparent, this seems to look better than
                       using every block */
                    if (auth && is_transparent(local_block)) {
                        average_gather += coeff;
                        average_count++;
                    }
                }
            }
        }
    }
    
    /* only return the average if at least one was authoratative */
    if (average_count > 0) {
        return average_gather / average_count;
    }
    
    blocklevel = get_data(state, BLOCKLIGHT, x, y, z);
    
    /* no longer a guess */
    if (!(block == 44 || block == 53 || block == 67 || block == 108 || block == 109) && authoratative) {
        *authoratative = 1;
    }
    
    return blocklevel;
}
Example #11
0
inline void
get_lighting_color(RenderPrimitiveLighting *self, RenderState *state,
                   int x, int y, int z,
                   unsigned char *r, unsigned char *g, unsigned char *b) {

    /* placeholders for later data arrays, coordinates */
    unsigned char block, skylevel, blocklevel;
    
    block = get_data(state, BLOCKS, x, y, z);
    skylevel = get_data(state, SKYLIGHT, x, y, z);
    blocklevel = get_data(state, BLOCKLIGHT, x, y, z);

    /* special half-step handling, stairs handling */
    /* Anvil also needs to be here, blockid 145 */
    if (block == 44 || block == 53 || block == 67 || block == 108 || block == 109 || block == 114 ||
        block == 128 || block == 134 || block == 135 || block == 136 || block == 145 || block == 156) {
        unsigned int upper_block;
        
        /* stairs and half-blocks take the skylevel from the upper block if it's transparent */
        int upper_counter = 0;
        /* but if the upper_block is one of these special half-steps, we need to look at *its* upper_block */
        do {
            upper_counter++; 
            upper_block = get_data(state, BLOCKS, x, y + upper_counter, z);
        } while (upper_block == 44 || upper_block == 53 || upper_block == 67 || upper_block == 108 ||
                 upper_block == 109 || upper_block == 114 || upper_block == 128 || upper_block == 134 ||
                 upper_block == 135 || upper_block == 136 || upper_block == 156 );
        if (is_transparent(upper_block)) {
            skylevel = get_data(state, SKYLIGHT, x, y + upper_counter, z);
        } else {
            skylevel = 15;
        }
        
        /* the block has a bad blocklevel, estimate it from neigborhood
         * use given coordinates, no local ones! */
        blocklevel = estimate_blocklevel(self, state, x, y, z, NULL);

    }
    
    if (block == 10 || block == 11) {
        /* lava blocks should always be lit! */
        *r = 255;
        *g = 255;
        *b = 255;
        return;
    }
    
    self->calculate_light_color(self, MIN(skylevel, 15), MIN(blocklevel, 15), r, g, b);
}
Example #12
0
void exposed_faces(
    Map *map, int x, int y, int z,
    int *f1, int *f2, int *f3, int *f4, int *f5, int *f6)
{
    *f1 = is_transparent(map_get(map, x - 1, y, z));
    *f2 = is_transparent(map_get(map, x + 1, y, z));
    *f3 = is_transparent(map_get(map, x, y + 1, z));
    *f4 = is_transparent(map_get(map, x, y - 1, z)) && (y > 0);
    *f5 = is_transparent(map_get(map, x, y, z + 1));
    *f6 = is_transparent(map_get(map, x, y, z - 1));
}
/* shades the drawn block with the given facemask/black_color, based on the
   lighting results from (x, y, z) */
static inline void
do_shading_with_mask(RenderModeLighting *self, RenderState *state,
                     int x, int y, int z, PyObject *mask) {
    float black_coeff;

    /* first, check for occlusion if the block is in the local chunk */
    if (x >= 0 && x < 16 && y >= 0 && y < 16 && z >= 0 && z < 128) {
        unsigned char block = getArrayByte3D(state->blocks, x, y, z);
        if (!is_transparent(block)) {
            /* this face isn't visible, so don't draw anything */
            return;
        }
    }
    
    black_coeff = get_lighting_coefficient(self, state, x, y, z, NULL);
    alpha_over_full(state->img, self->black_color, mask, black_coeff, state->imgx, state->imgy, 0, 0);
}
Example #14
0
//===========================================================================================================//
//    Utility Functions                                                                                      //
//===========================================================================================================//
	void rex_sprite::flatten() {
		if (num_layers == 1)
			return;

		//Paint the last layer onto the second-to-last
		for (int i = 0; i < width*height; ++i) {
			rltk::vchar* overlay = get_tile(num_layers - 1, i);
			if (!is_transparent(overlay)) {
				*get_tile(num_layers - 2, i) = *overlay;
			}
		}

		//Remove the last layer
		--num_layers;

		//Recurse
		flatten();
	}	
Example #15
0
void
overlay_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObject *mask_light) {
    RenderPrimitiveOverlay *self = (RenderPrimitiveOverlay *)data;
    unsigned char r, g, b, a;
    unsigned short top_block;

    // exactly analogous to edge-line code for these special blocks
    int increment=0;
    if (state->block == 44)  // half-step
        increment=6;
    else if (state->block == 78) // snow
        increment=9;
    
    /* skip rendering the overlay if we can't see it */
    top_block = get_data(state, BLOCKS, state->x, state->y+1, state->z);
    if (!is_transparent(top_block)) {
        return;
    }
    
    /* check to be sure this block is solid/fluid */
    if (block_has_property(top_block, SOLID) || block_has_property(top_block, FLUID)) {
        
        /* top block is fluid or solid, skip drawing */
        return;
    }
    
    /* check to be sure this block is solid/fluid */
    if (!block_has_property(state->block, SOLID) && !block_has_property(state->block, FLUID)) {
        
        /* not fluid or solid, skip drawing the overlay */
        return;
    }

    /* get our color info */
    self->get_color(data, state, &r, &g, &b, &a);
    
    /* do the overlay */
    if (a > 0) {
        alpha_over_full(state->img, self->white_color, self->facemask_top, a/255.f, state->imgx, state->imgy + increment, 0, 0);
        tint_with_mask(state->img, r, g, b, 255, self->facemask_top, state->imgx, state->imgy + increment, 0, 0);
    }
}
static void
rendermode_lighting_draw(void *data, RenderState *state, PyObject *src, PyObject *mask) {
    RenderModeLighting* self;
    int x, y, z;

    /* first, chain up */
    rendermode_normal.draw(data, state, src, mask);
    
    self = (RenderModeLighting *)data;
    x = state->x, y = state->y, z = state->z;
    
    if (is_transparent(state->block)) {
        /* transparent: do shading on whole block */
        do_shading_with_mask(self, state, x, y, z, mask);
    } else {
        /* opaque: do per-face shading */
        do_shading_with_mask(self, state, x, y, z+1, self->facemasks[0]);
        do_shading_with_mask(self, state, x-1, y, z, self->facemasks[1]);
        do_shading_with_mask(self, state, x, y+1, z, self->facemasks[2]);
    }
}
static void
rendermode_smooth_lighting_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObject *mask_light) {
    int light_top = 1;
    int light_left = 1;
    int light_right = 1;
    RenderModeSmoothLighting *self = (RenderModeSmoothLighting *)data;
    
    /* special case for leaves, water 8, water 9
       -- these are also smooth-lit! */
    if (state->block != 18 && state->block != 8 && state->block != 9 && is_transparent(state->block))
    {
        /* transparent blocks are rendered as usual, with flat lighting */
        rendermode_lighting.draw(data, state, src, mask, mask_light);
        return;
    }
    
    /* non-transparent blocks get the special smooth treatment */
    
    /* nothing special to do, but we do want to avoid vanilla
     * lighting mode draws */
    rendermode_normal.draw(data, state, src, mask, mask_light);
    
    /* special code for water */
    if (state->block == 9)
    {
        if (!(state->block_pdata & (1 << 4)))
            light_top = 0;
        if (!(state->block_pdata & (1 << 1)))
            light_left = 0;
        if (!(state->block_pdata & (1 << 2)))
            light_right = 0;
    }
    
    if (light_top)
        do_shading_with_rule(self, state, lighting_rules[FACE_TOP]);
    if (light_left)
        do_shading_with_rule(self, state, lighting_rules[FACE_LEFT]);
    if (light_right)
        do_shading_with_rule(self, state, lighting_rules[FACE_RIGHT]);
}
inline unsigned char
estimate_blocklevel(RenderModeLighting *self, RenderState *state,
                         int x, int y, int z, int *authoratative) {

    /* placeholders for later data arrays, coordinates */
    PyObject *blocks = NULL;
    PyObject *blocklight = NULL;
    int local_x = x, local_y = y, local_z = z;
    unsigned char block, blocklevel;
    unsigned int average_count = 0, average_gather = 0, coeff = 0;

    /* defaults to "guess" until told otherwise */
    if (authoratative)
        *authoratative = 0;
    
    /* find out what chunk we're in, and translate accordingly */
    if (x >= 0 && y < 16) {
        blocks = state->blocks;
        blocklight = self->blocklight;
    } else if (x < 0) {
        local_x += 16;        
        blocks = state->left_blocks;
        blocklight = self->left_blocklight;
    } else if (y >= 16) {
        local_y -= 16;
        blocks = state->right_blocks;
        blocklight = self->right_blocklight;
    }
    
    /* make sure we have correctly-ranged coordinates */
    if (!(local_x >= 0 && local_x < 16 &&
          local_y >= 0 && local_y < 16 &&
          local_z >= 0 && local_z < 128)) {
        
        return 0;
    }

    /* also, make sure we have enough info to correctly calculate lighting */
    if (blocks == Py_None || blocks == NULL ||
        blocklight == Py_None || blocklight == NULL) {
        
        return 0;
    }

    block = getArrayByte3D(blocks, local_x, local_y, local_z);
    
    if (authoratative == NULL) {
        int auth;
        
        /* iterate through all surrounding blocks to take an average */
        int dx, dy, dz, local_block;
        for (dx = -1; dx <= 1; dx += 2) {
            for (dy = -1; dy <= 1; dy += 2) {
                for (dz = -1; dz <= 1; dz += 2) {
                    
                    /* skip if block is out of range */
                    if (x+dx < 0 || x+dx >= 16 ||
                        y+dy < 0 || y+dy >= 16 ||
                        z+dz < 0 || z+dz >= 128) {
                        continue;
                    }

                    coeff = estimate_blocklevel(self, state, x+dx, y+dy, z+dz, &auth);
                    local_block = getArrayByte3D(blocks, x+dx, y+dy, z+dz);
                    /* only add if the block is transparent, this seems to look better than
                       using every block */
                    if (auth && is_transparent(local_block)) {
                        average_gather += coeff;
                        average_count++;
                    }
                }
            }
        }
    }
    
    /* only return the average if at least one was authoratative */
    if (average_count > 0) {
        return average_gather / average_count;
    }
    
    blocklevel = getArrayByte3D(blocklight, local_x, local_y, local_z);
    
    /* no longer a guess */
    if (!(block == 44 || block == 53 || block == 67) && authoratative) {
        *authoratative = 1;
    }
    
    return blocklevel;
}
inline float
get_lighting_coefficient(RenderModeLighting *self, RenderState *state,
                         int x, int y, int z) {

    /* placeholders for later data arrays, coordinates */
    PyObject *blocks = NULL;
    PyObject *skylight = NULL;
    PyObject *blocklight = NULL;
    int local_x = x, local_y = y, local_z = z;
    unsigned char block, skylevel, blocklevel;

    /* find out what chunk we're in, and translate accordingly */
    if (x >= 0 && y < 16) {
        blocks = state->blocks;
        skylight = self->skylight;
        blocklight = self->blocklight;
    } else if (x < 0) {
        local_x += 16;        
        blocks = state->left_blocks;
        skylight = self->left_skylight;
        blocklight = self->left_blocklight;
    } else if (y >= 16) {
        local_y -= 16;
        blocks = state->right_blocks;
        skylight = self->right_skylight;
        blocklight = self->right_blocklight;
    }

    /* make sure we have correctly-ranged coordinates */
    if (!(local_x >= 0 && local_x < 16 &&
          local_y >= 0 && local_y < 16 &&
          local_z >= 0 && local_z < 128)) {
        
        return self->calculate_darkness(15, 0);
    }

    /* also, make sure we have enough info to correctly calculate lighting */
    if (blocks == Py_None || blocks == NULL ||
        skylight == Py_None || skylight == NULL ||
        blocklight == Py_None || blocklight == NULL) {
        
        return self->calculate_darkness(15, 0);
    }
    
    block = getArrayByte3D(blocks, local_x, local_y, local_z);
    
    /* if this block is opaque, use a fully-lit coeff instead
       to prevent stippled lines along chunk boundaries! */
    if (!is_transparent(block)) {
        return self->calculate_darkness(15, 0);
    }
    
    skylevel = getArrayByte3D(skylight, local_x, local_y, local_z);
    blocklevel = getArrayByte3D(blocklight, local_x, local_y, local_z);

    /* special half-step handling */
    if (block == 44 || block == 53 || block == 67) {
        unsigned int upper_block;
        
        /* stairs and half-blocks take the skylevel from the upper block if it's transparent */
        if (local_z != 127) {
            int upper_counter = 0;
            /* but if the upper_block is one of these special half-steps, we need to look at *its* upper_block */
            do {
                upper_counter++; 
                upper_block = getArrayByte3D(blocks, local_x, local_y, local_z + upper_counter);
            } while ((upper_block == 44 || upper_block == 54 || upper_block == 67) && local_z < 127);
            if (is_transparent(upper_block)) {
                skylevel = getArrayByte3D(skylight, local_x, local_y, local_z + upper_counter);
            }
        } else {
            upper_block = 0;
            skylevel = 15;
        }
        
        /* the block has a bad blocklevel, estimate it from neigborhood
         * use given coordinates, no local ones! */
        blocklevel = estimate_blocklevel(self, state, x, y, z, NULL);

    }
    
    if (block == 10 || block == 11) {
        /* lava blocks should always be lit! */
        return 0.0f;
    }
    
    return self->calculate_darkness(skylevel, blocklevel);
}
Example #20
0
void WorkerItem::computeChunk(World *world)
{
    char *opaque = (char *)calloc(XZ_SIZE * XZ_SIZE * Y_SIZE, sizeof(float));
    char *light = (char *)calloc(XZ_SIZE * XZ_SIZE * Y_SIZE, sizeof(char));
    char *highest = (char *)calloc(XZ_SIZE * XZ_SIZE, sizeof(char));
    
    int ox = p * CHUNK_SIZE - CHUNK_SIZE - 1;
    int oy = -1;
    int oz = q * CHUNK_SIZE - CHUNK_SIZE - 1;
    
    // check for lights
    int has_light = 0;
    if (SHOW_LIGHTS) {
        for (int a = 0; a < 3; a++) {
            for (int b = 0; b < 3; b++) {
                Map *map = light_maps[a][b];
                if (map && map->size) {
                    has_light = 1;
                }
            }
        }
    }
    
    // populate opaque array
    for (int a = 0; a < 3; a++) {
        for (int b = 0; b < 3; b++) {
            Map *map = block_maps[a][b];
            if (!map) {
                continue;
            }
            MAP_FOR_EACH(map, ex, ey, ez, ew) {
                
                int rawx = Map::getX(i);
                int rawy = Map::getY(i);
                int rawz = Map::getZ(i);
                
                int x2 = rawx + map->dx - ox;
                int y2 = rawy + map->dy - oy;
                int z2 = rawz + map->dz - oz;
                
                int x = 0;
                int y = 0;
                int z = 0;
                
                if(entry->e.computed)
                {
                    x = x2;
                    y = y2;
                    z = z2;
                }

                int w = ew;
                // TODO: this should be unnecessary
                if (x < 0 || y < 0 || z < 0) {
                    continue;
                }
                if (x >= XZ_SIZE || y >= Y_SIZE || z >= XZ_SIZE) {
                    continue;
                }
                // END TODO
                opaque[XYZ(x, y, z)] = !is_transparent(w);
                if (opaque[XYZ(x, y, z)]) {
                    highest[XZ(x, z)] = MAX(highest[XZ(x, z)], y);
                }
            } END_MAP_FOR_EACH;
        }
    }
static void
rendermode_normal_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObject *mask_light) {
    RenderModeNormal *self = (RenderModeNormal *)data;

    /* draw the block! */
    alpha_over(state->img, src, mask, state->imgx, state->imgy, 0, 0);
    
    /* check for biome-compatible blocks
     *
     * NOTES for maintainers:
     *
     * To add a biome-compatible block, add an OR'd condition to this
     * following if block, a case to the first switch statement to handle when
     * biome info IS available, and another case to the second switch
     * statement for when biome info ISN'T available.
     *
     * Make sure that in textures.py, the generated textures are the
     * biome-compliant ones! The tinting is now all done here.
     */
    if (/* grass, but not snowgrass */
        (state->block == 2 && !(state->z < 127 && getArrayByte3D(state->blocks, state->x, state->y, state->z+1) == 78)) ||
        /* water */
        state->block == 8 || state->block == 9 ||
        /* leaves */
        state->block == 18 ||
        /* tallgrass, but not dead shrubs */
        (state->block == 31 && state->block_data != 0) ||
        /* pumpkin/melon stem, not fully grown. Fully grown stems
         * get constant brown color (see textures.py) */
        (((state->block == 104) || (state->block == 105)) && (state->block_data != 7)) ||
        /* vines */
        state->block == 106 ||
        /* lily pads */
        state->block == 111)
    {
        /* do the biome stuff! */
        PyObject *facemask = mask;
        unsigned char r, g, b;
        
        if (state->block == 2) {
            /* grass needs a special facemask */
            facemask = self->grass_texture;
        }
        
        if (self->biome_data) {
            /* we have data, so use it! */
            unsigned int index;
            PyObject *color = NULL;
            
            index = ((self->chunk_y * 16) + state->y) * 16 * 32 + (self->chunk_x * 16) + state->x;
            index = big_endian_ushort(getArrayShort1D(self->biome_data, index));
            
            switch (state->block) {
            case 2:
                /* grass */
                color = PySequence_GetItem(self->grasscolor, index);
                break;
            case 8:
            case 9:
                /* water */
                if (self->watercolor)
                {
                    color = PySequence_GetItem(self->watercolor, index);
                } else {
                    color = NULL;
                    facemask = NULL;
                }
                break;
            case 18:
                /* leaves */
                if (state->block_data != 2)
                {
                    /* not birch! */
                    color = PySequence_GetItem(self->foliagecolor, index);
                } else {
                    /* birch!
                       birch foliage color is flipped XY-ways */
                    unsigned int index_x = 255 - (index % 256);
                    unsigned int index_y = 255 - (index / 256);
                    index = index_y * 256 + index_x;
                    
                    color = PySequence_GetItem(self->foliagecolor, index);
                }
                break;
            case 31:
                /* tall grass */
                color = PySequence_GetItem(self->grasscolor, index);
                break;
            case 104:
                /* pumpkin stem */
                color = PySequence_GetItem(self->grasscolor, index);
                break;
            case 105:
                /* melon stem */
                color = PySequence_GetItem(self->grasscolor, index);
                break;
            case 106:
                /* vines */
                color = PySequence_GetItem(self->grasscolor, index);
                break;
            case 111:
                /* lily padas */
                color = PySequence_GetItem(self->grasscolor, index);
                break;
            default:
                break;
            };
            
            if (color)
            {
                /* we've got work to do */
                
                r = PyInt_AsLong(PyTuple_GET_ITEM(color, 0));
                g = PyInt_AsLong(PyTuple_GET_ITEM(color, 1));
                b = PyInt_AsLong(PyTuple_GET_ITEM(color, 2));
                Py_DECREF(color);
            }
        } else {
            if (state->block == 2 || state->block == 31 ||
                state->block == 104 || state->block == 105)
                /* grass and pumpkin/melon stems */
            {
                r = 115;
                g = 175;
                b = 71;
            }
            
            if (state->block == 8 || state->block == 9)
                /* water */
            {
                /* by default water is fine with nothing */
                facemask = NULL;
            }
            
            if (state->block == 18 || state->block == 106 || state->block == 111)
                /* leaves, vines and lyli pads */
            {
                r = 37;
                g = 118;
                b = 25;
            }
        }
        
        if (facemask)
            tint_with_mask(state->img, r, g, b, 255, facemask, state->imgx, state->imgy, 0, 0);
    }
    
    if (self->height_fading) {
        /* do some height fading */
        PyObject *height_color = self->white_color;
        /* negative alpha => darkness, positive => light */
        float alpha = (1.0 / (1 + expf((70 - state->z) / 11.0))) * 0.6 - 0.55;
        
        if (alpha < 0.0) {
            alpha *= -1;
            height_color = self->black_color;
        }
        
        alpha_over_full(state->img, height_color, mask_light, alpha, state->imgx, state->imgy, 0, 0);
    }
    

    /* Draw some edge lines! */
    // draw.line(((imgx+12,imgy+increment), (imgx+22,imgy+5+increment)), fill=(0,0,0), width=1)
    if (state->block == 44 || state->block == 78 || !is_transparent(state->block)) {
        Imaging img_i = imaging_python_to_c(state->img);
        unsigned char ink[] = {0, 0, 0, 255 * self->edge_opacity};

        int increment=0;
        if (state->block == 44)  // half-step
            increment=6;
        else if ((state->block == 78) || (state->block == 93) || (state->block == 94)) // snow, redstone repeaters (on and off)
            increment=9;

        if ((state->x == 15) && (state->up_right_blocks != Py_None)) {
            unsigned char side_block = getArrayByte3D(state->up_right_blocks, 0, state->y, state->z);
            if (side_block != state->block && is_transparent(side_block)) {
                ImagingDrawLine(img_i, state->imgx+12, state->imgy+1+increment, state->imgx+22+1, state->imgy+5+1+increment, &ink, 1);
                ImagingDrawLine(img_i, state->imgx+12, state->imgy+increment, state->imgx+22+1, state->imgy+5+increment, &ink, 1);
            }
        } else if (state->x != 15) {
            unsigned char side_block = getArrayByte3D(state->blocks, state->x+1, state->y, state->z);
            if (side_block != state->block && is_transparent(side_block)) {
                ImagingDrawLine(img_i, state->imgx+12, state->imgy+1+increment, state->imgx+22+1, state->imgy+5+1+increment, &ink, 1);
                ImagingDrawLine(img_i, state->imgx+12, state->imgy+increment, state->imgx+22+1, state->imgy+5+increment, &ink, 1);
            }
        }
        // if y != 0 and blocks[x,y-1,z] == 0

        // chunk boundries are annoying
        if ((state->y == 0) && (state->up_left_blocks != Py_None)) {
            unsigned char side_block = getArrayByte3D(state->up_left_blocks, state->x, 15, state->z);
            if (side_block != state->block && is_transparent(side_block)) {
                ImagingDrawLine(img_i, state->imgx, state->imgy+6+1+increment, state->imgx+12+1, state->imgy+1+increment, &ink, 1);
                ImagingDrawLine(img_i, state->imgx, state->imgy+6+increment, state->imgx+12+1, state->imgy+increment, &ink, 1);
            }
        } else if (state->y != 0) {
            unsigned char side_block = getArrayByte3D(state->blocks, state->x, state->y-1, state->z);
            if (side_block != state->block && is_transparent(side_block)) {
                // draw.line(((imgx,imgy+6+increment), (imgx+12,imgy+increment)), fill=(0,0,0), width=1)
                ImagingDrawLine(img_i, state->imgx, state->imgy+6+1+increment, state->imgx+12+1, state->imgy+1+increment, &ink, 1);
                ImagingDrawLine(img_i, state->imgx, state->imgy+6+increment, state->imgx+12+1, state->imgy+increment, &ink, 1);
            }
        }
    }
}
Example #22
0
Array VoxelMesher::build(const VoxelBuffer &buffer, unsigned int channel, Vector3i min, Vector3i max) {
	uint64_t time_before = OS::get_singleton()->get_ticks_usec();

	ERR_FAIL_COND_V(_library.is_null(), Array());
	ERR_FAIL_COND_V(channel >= VoxelBuffer::MAX_CHANNELS, Array());

	const VoxelLibrary &library = **_library;

	for (unsigned int i = 0; i < MAX_MATERIALS; ++i) {
		Arrays &a = _arrays[i];
		a.positions.clear();
		a.normals.clear();
		a.uvs.clear();
		a.colors.clear();
		a.indices.clear();
	}

	float baked_occlusion_darkness;
	if (_bake_occlusion)
		baked_occlusion_darkness = _baked_occlusion_darkness / 3.0;

	// The technique is Culled faces.
	// Could be improved with greedy meshing: https://0fps.net/2012/06/30/meshing-in-a-minecraft-game/
	// However I don't feel it's worth it yet:
	// - Not so much gain for organic worlds with lots of texture variations
	// - Works well with cubes but not with any shape
	// - Slower
	// => Could be implemented in a separate class?

	// Data must be padded, hence the off-by-one
	Vector3i::sort_min_max(min, max);
	const Vector3i pad(1, 1, 1);
	min.clamp_to(pad, max);
	max.clamp_to(min, buffer.get_size() - pad);

	int index_offset = 0;

	// Iterate 3D padded data to extract voxel faces.
	// This is the most intensive job in this class, so all required data should be as fit as possible.

	// The buffer we receive MUST be dense (i.e not compressed, and channels allocated).
	// That means we can use raw pointers to voxel data inside instead of using the higher-level getters,
	// and then save a lot of time.

	uint8_t *type_buffer = buffer.get_channel_raw(Voxel::CHANNEL_TYPE);
	//       _
	//      | \
	//     /\ \\
	//    / /|\\\
	//    | |\ \\\
	//    | \_\ \\|
	//    |    |  )
	//     \   |  |
	//      \    /
	CRASH_COND(type_buffer == NULL);


	//CRASH_COND(memarr_len(type_buffer) != buffer.get_volume() * sizeof(uint8_t));

	// Build lookup tables so to speed up voxel access.
	// These are values to add to an address in order to get given neighbor.

	int row_size = buffer.get_size().y;
	int deck_size = buffer.get_size().x * row_size;

	int side_neighbor_lut[Cube::SIDE_COUNT];
	side_neighbor_lut[Cube::SIDE_LEFT] = row_size;
	side_neighbor_lut[Cube::SIDE_RIGHT] = -row_size;
	side_neighbor_lut[Cube::SIDE_BACK] = -deck_size;
	side_neighbor_lut[Cube::SIDE_FRONT] = deck_size;
	side_neighbor_lut[Cube::SIDE_BOTTOM] = -1;
	side_neighbor_lut[Cube::SIDE_TOP] = 1;

	int edge_neighbor_lut[Cube::EDGE_COUNT];
	edge_neighbor_lut[Cube::EDGE_BOTTOM_BACK] = side_neighbor_lut[Cube::SIDE_BOTTOM] + side_neighbor_lut[Cube::SIDE_BACK];
	edge_neighbor_lut[Cube::EDGE_BOTTOM_FRONT] = side_neighbor_lut[Cube::SIDE_BOTTOM] + side_neighbor_lut[Cube::SIDE_FRONT];
	edge_neighbor_lut[Cube::EDGE_BOTTOM_LEFT] = side_neighbor_lut[Cube::SIDE_BOTTOM] + side_neighbor_lut[Cube::SIDE_LEFT];
	edge_neighbor_lut[Cube::EDGE_BOTTOM_RIGHT] = side_neighbor_lut[Cube::SIDE_BOTTOM] + side_neighbor_lut[Cube::SIDE_RIGHT];
	edge_neighbor_lut[Cube::EDGE_BACK_LEFT] = side_neighbor_lut[Cube::SIDE_BACK] + side_neighbor_lut[Cube::SIDE_LEFT];
	edge_neighbor_lut[Cube::EDGE_BACK_RIGHT] = side_neighbor_lut[Cube::SIDE_BACK] + side_neighbor_lut[Cube::SIDE_RIGHT];
	edge_neighbor_lut[Cube::EDGE_FRONT_LEFT] = side_neighbor_lut[Cube::SIDE_FRONT] + side_neighbor_lut[Cube::SIDE_LEFT];
	edge_neighbor_lut[Cube::EDGE_FRONT_RIGHT] = side_neighbor_lut[Cube::SIDE_FRONT] + side_neighbor_lut[Cube::SIDE_RIGHT];
	edge_neighbor_lut[Cube::EDGE_TOP_BACK] = side_neighbor_lut[Cube::SIDE_TOP] + side_neighbor_lut[Cube::SIDE_BACK];
	edge_neighbor_lut[Cube::EDGE_TOP_FRONT] = side_neighbor_lut[Cube::SIDE_TOP] + side_neighbor_lut[Cube::SIDE_FRONT];
	edge_neighbor_lut[Cube::EDGE_TOP_LEFT] = side_neighbor_lut[Cube::SIDE_TOP] + side_neighbor_lut[Cube::SIDE_LEFT];
	edge_neighbor_lut[Cube::EDGE_TOP_RIGHT] = side_neighbor_lut[Cube::SIDE_TOP] + side_neighbor_lut[Cube::SIDE_RIGHT];

	int corner_neighbor_lut[Cube::CORNER_COUNT];
	corner_neighbor_lut[Cube::CORNER_BOTTOM_BACK_LEFT] = side_neighbor_lut[Cube::SIDE_BOTTOM] + side_neighbor_lut[Cube::SIDE_BACK] + side_neighbor_lut[Cube::SIDE_LEFT];
	corner_neighbor_lut[Cube::CORNER_BOTTOM_BACK_RIGHT] = side_neighbor_lut[Cube::SIDE_BOTTOM] + side_neighbor_lut[Cube::SIDE_BACK] + side_neighbor_lut[Cube::SIDE_RIGHT];
	corner_neighbor_lut[Cube::CORNER_BOTTOM_FRONT_RIGHT] = side_neighbor_lut[Cube::SIDE_BOTTOM] + side_neighbor_lut[Cube::SIDE_FRONT] + side_neighbor_lut[Cube::SIDE_RIGHT];
	corner_neighbor_lut[Cube::CORNER_BOTTOM_FRONT_LEFT] = side_neighbor_lut[Cube::SIDE_BOTTOM] + side_neighbor_lut[Cube::SIDE_FRONT] + side_neighbor_lut[Cube::SIDE_LEFT];
	corner_neighbor_lut[Cube::CORNER_TOP_BACK_LEFT] = side_neighbor_lut[Cube::SIDE_TOP] + side_neighbor_lut[Cube::SIDE_BACK] + side_neighbor_lut[Cube::SIDE_LEFT];
	corner_neighbor_lut[Cube::CORNER_TOP_BACK_RIGHT] = side_neighbor_lut[Cube::SIDE_TOP] + side_neighbor_lut[Cube::SIDE_BACK] + side_neighbor_lut[Cube::SIDE_RIGHT];
	corner_neighbor_lut[Cube::CORNER_TOP_FRONT_RIGHT] = side_neighbor_lut[Cube::SIDE_TOP] + side_neighbor_lut[Cube::SIDE_FRONT] + side_neighbor_lut[Cube::SIDE_RIGHT];
	corner_neighbor_lut[Cube::CORNER_TOP_FRONT_LEFT] = side_neighbor_lut[Cube::SIDE_TOP] + side_neighbor_lut[Cube::SIDE_FRONT] + side_neighbor_lut[Cube::SIDE_LEFT];

	uint64_t time_prep = OS::get_singleton()->get_ticks_usec() - time_before;
	time_before = OS::get_singleton()->get_ticks_usec();

	for (unsigned int z = min.z; z < max.z; ++z) {
		for (unsigned int x = min.x; x < max.x; ++x) {
			for (unsigned int y = min.y; y < max.y; ++y) {
				// min and max are chosen such that you can visit 1 neighbor away from the current voxel without size check

				// TODO In this intensive routine, there is a way to make voxel access fastest by getting a pointer to the channel,
				// and using offset lookup to get neighbors rather than going through get_voxel validations
				int voxel_index = y + x * row_size + z * deck_size;
				int voxel_id = type_buffer[voxel_index];

				if (voxel_id != 0 && library.has_voxel(voxel_id)) {

					const Voxel &voxel = library.get_voxel_const(voxel_id);

					Arrays &arrays = _arrays[voxel.get_material_id()];

					// Hybrid approach: extract cube faces and decimate those that aren't visible,
					// and still allow voxels to have geometry that is not a cube

					// Sides
					for (unsigned int side = 0; side < Cube::SIDE_COUNT; ++side) {

						const PoolVector<Vector3> &positions = voxel.get_model_side_positions(side);
						int vertex_count = positions.size();

						if (vertex_count != 0) {

							int neighbor_voxel_id = type_buffer[voxel_index + side_neighbor_lut[side]];

							// TODO Better face visibility test
							if (is_face_visible(library, voxel, neighbor_voxel_id)) {

								// The face is visible

								int shaded_corner[8] = { 0 };

								if (_bake_occlusion) {

									// Combinatory solution for https://0fps.net/2013/07/03/ambient-occlusion-for-minecraft-like-worlds/

									for (unsigned int j = 0; j < 4; ++j) {
										unsigned int edge = Cube::g_side_edges[side][j];
										int edge_neighbor_id = type_buffer[voxel_index + edge_neighbor_lut[edge]];
										if (!is_transparent(library, edge_neighbor_id)) {
											shaded_corner[Cube::g_edge_corners[edge][0]] += 1;
											shaded_corner[Cube::g_edge_corners[edge][1]] += 1;
										}
									}
									for (unsigned int j = 0; j < 4; ++j) {
										unsigned int corner = Cube::g_side_corners[side][j];
										if (shaded_corner[corner] == 2) {
											shaded_corner[corner] = 3;
										} else {
											int corner_neigbor_id = type_buffer[voxel_index + corner_neighbor_lut[corner]];
											if (!is_transparent(library, corner_neigbor_id)) {
												shaded_corner[corner] += 1;
											}
										}
									}
								}

								PoolVector<Vector3>::Read rv = positions.read();
								PoolVector<Vector2>::Read rt = voxel.get_model_side_uv(side).read();

								// Subtracting 1 because the data is padded
								Vector3 pos(x - 1, y - 1, z - 1);

								// Append vertices of the faces in one go, don't use push_back

								{
									int append_index = arrays.positions.size();
									arrays.positions.resize(arrays.positions.size() + vertex_count);
									Vector3 *w = arrays.positions.ptrw() + append_index;
									for (unsigned int i = 0; i < vertex_count; ++i) {
										w[i] = rv[i] + pos;
									}
								}

								{
									int append_index = arrays.uvs.size();
									arrays.uvs.resize(arrays.uvs.size() + vertex_count);
									memcpy(arrays.uvs.ptrw() + append_index, rt.ptr(), vertex_count * sizeof(Vector2));
								}

								{
									int append_index = arrays.normals.size();
									arrays.normals.resize(arrays.normals.size() + vertex_count);
									Vector3 *w = arrays.normals.ptrw() + append_index;
									for (unsigned int i = 0; i < vertex_count; ++i) {
										w[i] = Cube::g_side_normals[side].to_vec3();
									}
								}

								if (_bake_occlusion) {
									// Use color array

									int append_index = arrays.colors.size();
									arrays.colors.resize(arrays.colors.size() + vertex_count);
									Color *w = arrays.colors.ptrw() + append_index;

									for (unsigned int i = 0; i < vertex_count; ++i) {
										Vector3 v = rv[i];

										// General purpose occlusion colouring.
										// TODO Optimize for cubes
										// TODO Fix occlusion inconsistency caused by triangles orientation? Not sure if worth it
										float shade = 0;
										for (unsigned int j = 0; j < 4; ++j) {
											unsigned int corner = Cube::g_side_corners[side][j];
											if (shaded_corner[corner]) {
												float s = baked_occlusion_darkness * static_cast<float>(shaded_corner[corner]);
												float k = 1.0 - Cube::g_corner_position[corner].distance_to(v);
												if (k < 0.0)
													k = 0.0;
												s *= k;
												if (s > shade)
													shade = s;
											}
										}
										float gs = 1.0 - shade;
										w[i] = Color(gs, gs, gs);
									}
								}

								const PoolVector<int> &side_indices = voxel.get_model_side_indices(side);
								PoolVector<int>::Read ri = side_indices.read();
								unsigned int index_count = side_indices.size();

								{
									int i = arrays.indices.size();
									arrays.indices.resize(arrays.indices.size() + index_count);
									int *w = arrays.indices.ptrw();
									for(unsigned int j = 0; j < index_count; ++j) {
										w[i++] = index_offset + ri[j];
									}
								}

								index_offset += vertex_count;
							}
						}
					}

					// Inside
					if (voxel.get_model_positions().size() != 0) {
						// TODO Get rid of push_backs

						const PoolVector<Vector3> &vertices = voxel.get_model_positions();
						int vertex_count = vertices.size();

						PoolVector<Vector3>::Read rv = vertices.read();
						PoolVector<Vector3>::Read rn = voxel.get_model_normals().read();
						PoolVector<Vector2>::Read rt = voxel.get_model_uv().read();

						Vector3 pos(x - 1, y - 1, z - 1);

						for (unsigned int i = 0; i < vertex_count; ++i) {
							arrays.normals.push_back(rn[i]);
							arrays.uvs.push_back(rt[i]);
							arrays.positions.push_back(rv[i] + pos);
						}

						if(_bake_occlusion) {
							// TODO handle ambient occlusion on inner parts
							arrays.colors.push_back(Color(1,1,1));
						}

						const PoolVector<int> &indices = voxel.get_model_indices();
						PoolVector<int>::Read ri = indices.read();
						unsigned int index_count = indices.size();

						for(unsigned int i = 0; i < index_count; ++i) {
							arrays.indices.push_back(index_offset + ri[i]);
						}

						index_offset += vertex_count;
					}
				}
			}
		}
	}

	uint64_t time_meshing = OS::get_singleton()->get_ticks_usec() - time_before;
	time_before = OS::get_singleton()->get_ticks_usec();

	// Commit mesh

//	print_line(String("Made mesh v: ") + String::num(_arrays[0].positions.size())
//			+ String(", i: ") + String::num(_arrays[0].indices.size()));

	Array surfaces;

	// TODO We could return a single byte array and use Mesh::add_surface down the line?

	for (int i = 0; i < MAX_MATERIALS; ++i) {

		const Arrays &arrays = _arrays[i];
		if (arrays.positions.size() != 0) {

			/*print_line("Arrays:");
			for(int i = 0; i < arrays.positions.size(); ++i)
				print_line(String("  P {0}").format(varray(arrays.positions[i])));
			for(int i = 0; i < arrays.normals.size(); ++i)
				print_line(String("  N {0}").format(varray(arrays.normals[i])));
			for(int i = 0; i < arrays.uvs.size(); ++i)
				print_line(String("  UV {0}").format(varray(arrays.uvs[i])));*/

			Array mesh_arrays;
			mesh_arrays.resize(Mesh::ARRAY_MAX);

			{
				PoolVector<Vector3> positions;
				PoolVector<Vector2> uvs;
				PoolVector<Vector3> normals;
				PoolVector<Color> colors;
				PoolVector<int> indices;

				raw_copy_to(positions, arrays.positions);
				raw_copy_to(uvs, arrays.uvs);
				raw_copy_to(normals, arrays.normals);
				raw_copy_to(colors, arrays.colors);
				raw_copy_to(indices, arrays.indices);

				mesh_arrays[Mesh::ARRAY_VERTEX] = positions;
				mesh_arrays[Mesh::ARRAY_TEX_UV] = uvs;
				mesh_arrays[Mesh::ARRAY_NORMAL] = normals;
				mesh_arrays[Mesh::ARRAY_COLOR] = colors;
				mesh_arrays[Mesh::ARRAY_INDEX] = indices;
			}

			surfaces.append(mesh_arrays);
		}
	}

	uint64_t time_commit = OS::get_singleton()->get_ticks_usec() - time_before;

	//print_line(String("P: {0}, M: {1}, C: {2}").format(varray(time_prep, time_meshing, time_commit)));

	return surfaces;
}
Example #23
0
gfx::Size Graphics::drawStringAlgorithm(const std::string& str, Color fg, Color bg, const gfx::Rect& rc, int align, bool draw)
{
  gfx::Point pt(0, rc.y);

  if ((align & (JI_MIDDLE | JI_BOTTOM)) != 0) {
    gfx::Size preSize = drawStringAlgorithm(str, ColorNone, ColorNone, rc, 0, false);
    if (align & JI_MIDDLE)
      pt.y = rc.y + rc.h/2 - preSize.h/2;
    else if (align & JI_BOTTOM)
      pt.y = rc.y + rc.h - preSize.h;
  }

  gfx::Size calculatedSize(0, 0);
  size_t beg, end, new_word_beg, old_end;
  std::string line;

  // Draw line-by-line
  for (beg=end=0; end != std::string::npos; ) {
    pt.x = rc.x;

    // Without word-wrap
    if ((align & JI_WORDWRAP) == 0) {
      end = str.find('\n', beg);
    }
    // With word-wrap
    else {
      old_end = std::string::npos;
      for (new_word_beg=beg;;) {
        end = str.find_first_of(" \n", new_word_beg);

        // If we have already a word to print (old_end != npos), and
        // we are out of the available width (rc.w) using the new "end",
        if ((old_end != std::string::npos) &&
            (pt.x+measureString(str.substr(beg, end-beg)).w > rc.w)) {
          // We go back to the "old_end" and paint from "beg" to "end"
          end = old_end;
          break;
        }
        // If we have more words to print...
        else if (end != std::string::npos) {
          // Force line break, now we have to paint from "beg" to "end"
          if (str[end] == '\n')
            break;

          // White-space, this is a beginning of a new word.
          new_word_beg = end+1;
        }
        // We are in the end of text
        else
          break;

        old_end = end;
      }
    }

    // Get the entire line to be painted
    line = str.substr(beg, end-beg);

    gfx::Size lineSize = measureString(line);
    calculatedSize.w = MAX(calculatedSize.w, lineSize.w);

    // Render the text
    if (draw) {
      int xout;
      if ((align & JI_CENTER) == JI_CENTER)
        xout = pt.x + rc.w/2 - lineSize.w/2;
      else if ((align & JI_RIGHT) == JI_RIGHT)
        xout = pt.x + rc.w - lineSize.w;
      else
        xout = pt.x;

      ji_font_set_aa_mode(m_currentFont, to_system(bg));
      textout_ex(m_bmp, m_currentFont, line.c_str(), m_dx+xout, m_dy+pt.y, to_system(fg), to_system(bg));

      if (!is_transparent(bg))
        fillAreaBetweenRects(bg,
          gfx::Rect(rc.x, pt.y, rc.w, lineSize.h),
          gfx::Rect(xout, pt.y, lineSize.w, lineSize.h));
    }

    pt.y += lineSize.h;
    calculatedSize.h += lineSize.h;
    beg = end+1;
  }

  // Fill bottom area
  if (draw && !is_transparent(bg)) {
    if (pt.y < rc.y+rc.h)
      fillRect(bg, gfx::Rect(rc.x, pt.y, rc.w, rc.y+rc.h-pt.y));
  }

  return calculatedSize;
}
/* loads the appropriate light data for the given (possibly non-local)
 * coordinates, and returns a black_coeff this is exposed, so other (derived)
 * rendermodes can use it
 *  
 * authoratative is a return slot for whether or not this lighting calculation
 * is true, or a guess. If we guessed, *authoratative will be false, but if it
 * was calculated correctly from available light data, it will be true. You
 * may (and probably should) pass NULL.
 */
inline float
get_lighting_coefficient(RenderModeLighting *self, RenderState *state,
                         int x, int y, int z, int *authoratative) {
    
    /* placeholders for later data arrays, coordinates */
    PyObject *blocks = NULL;
    PyObject *skylight = NULL;
    PyObject *blocklight = NULL;
    int local_x = x, local_y = y, local_z = z;
    unsigned char block, skylevel, blocklevel;
    
    /* defaults to "guess" until told otherwise */
    if (authoratative)
        *authoratative = 0;
    
    /* find out what chunk we're in, and translate accordingly */
    if (x >= 0 && y < 16) {
        blocks = state->blocks;
        skylight = self->skylight;
        blocklight = self->blocklight;
    } else if (x < 0) {
        local_x += 16;        
        blocks = state->left_blocks;
        skylight = self->left_skylight;
        blocklight = self->left_blocklight;
    } else if (y >= 16) {
        local_y -= 16;
        blocks = state->right_blocks;
        skylight = self->right_skylight;
        blocklight = self->right_blocklight;
    }
    
    /* make sure we have correctly-ranged coordinates */
    if (!(local_x >= 0 && local_x < 16 &&
          local_y >= 0 && local_y < 16 &&
          local_z >= 0 && local_z < 128)) {
        
        return self->calculate_darkness(15, 0);
    }
    
    /* also, make sure we have enough info to correctly calculate lighting */
    if (blocks == Py_None || blocks == NULL ||
        skylight == Py_None || skylight == NULL ||
        blocklight == Py_None || blocklight == NULL) {
        
        return self->calculate_darkness(15, 0);
    }
    
    block = getArrayByte3D(blocks, local_x, local_y, local_z);
    
    /* if this block is opaque, use a fully-lit coeff instead
       to prevent stippled lines along chunk boundaries! */
    if (!is_transparent(block)) {
        return self->calculate_darkness(15, 0);
    }
    
    /* only do special half-step handling if no authoratative pointer was
       passed in, which is a sign that we're recursing */
    if (block == 44 && authoratative == NULL) {
        float average_gather = 0.0f;
        unsigned int average_count = 0;
        int auth;
        float coeff;
        
        /* iterate through all surrounding blocks to take an average */
        int dx, dy, dz;
        for (dx = -1; dx <= 1; dx += 2) {
            for (dy = -1; dy <= 1; dy += 2) {
                for (dz = -1; dz <= 1; dz += 2) {
                    coeff = get_lighting_coefficient(self, state, x+dx, y+dy, z+dz, &auth);
                    if (auth) {
                        average_gather += coeff;
                        average_count++;
                    }
                }
            }
        }
        
        /* only return the average if at least one was authoratative */
        if (average_count > 0)
            return average_gather / average_count;
    }
    
    if (block == 10 || block == 11) {
        /* lava blocks should always be lit! */
        return 0.0f;
    }
    
    skylevel = getArrayByte3D(skylight, local_x, local_y, local_z);
    blocklevel = getArrayByte3D(blocklight, local_x, local_y, local_z);
    
    /* no longer a guess */
    if (authoratative)
        *authoratative = 1;
    
    return self->calculate_darkness(skylevel, blocklevel);
}
Example #25
0
bool LOSfinder::bresen_y(PosPoint source, PosPoint target)
{
    int x = source.posx;
    int error = 0;
    int delta_y = std::abs(source.posy - target.posy);
    int deltaerr = std::abs(source.posx - target.posx);
    int deltastep = sign(target.posx - source.posx);
    int incrstep = sign(target.posy - source.posy);
    for (int y = source.posy; y != target.posy; y += incrstep)
    {
        if ((x % RAY_MULTIPLIER) == 0 && (y % RAY_MULTIPLIER) == 0)
        {
            // when in corner check side neighbours
            // if both of them are not transparent then corner is not transparent
            PosPoint left_neighbour(x + deltastep, y, source.posz);
            PosPoint right_neighbour(x, y + incrstep, source.posz);
            if (!is_transparent(left_neighbour) && !is_transparent(right_neighbour))
            {
                return false;
            }
        }
        else if (x % RAY_MULTIPLIER == 0)
        {
            // when ray hits an edge check both tiles. Since ray travels through edge both of them 
            // must be transparent
            PosPoint left_neighbour(x - deltastep, y, source.posz);
            PosPoint right_neighbour(x + deltastep, y, source.posz);
            if (!is_transparent(left_neighbour) || !is_transparent(right_neighbour))
            {
                return false;
            }
        }
        else if (y % RAY_MULTIPLIER == 0)
        {
            // second case of edge handling
            PosPoint left_neighbour(x, y - incrstep, source.posz);
            PosPoint right_neighbour(x, y + incrstep, source.posz);
            if (!is_transparent(left_neighbour) || !is_transparent(right_neighbour))
            {
                return false;
            }
        }
        else
        {
            PosPoint new_point(x, y, source.posz);

            if (!is_transparent(new_point))
            {
                return false;
            }
        }

        error += deltaerr;
        if (error >= delta_y)
        {
            x += deltastep;
            error -= delta_y;
        }
    }

    return true;
}