Beispiel #1
0
void map::apply_character_light( const player &p )
{
    float const held_luminance = p.active_light();
    if( held_luminance > LIGHT_AMBIENT_LOW ) {
        apply_light_source( p.posx(), p.posy(), held_luminance, trigdist );
    }
}
Beispiel #2
0
void map::apply_character_light( player &p )
{
    if( p.has_effect( effect_onfire ) ) {
        apply_light_source( p.pos(), 8 );
    } else if( p.has_effect( effect_haslight ) ) {
        apply_light_source( p.pos(), 4 );
    }

    float const held_luminance = p.active_light();
    if( held_luminance > LIGHT_AMBIENT_LOW ) {
        apply_light_source( p.pos(), held_luminance );
    }

    if( held_luminance >= 4 && held_luminance > ambient_light_at( p.pos() ) - 0.5f ) {
        p.add_effect( effect_haslight, 1 );
    }
}
Beispiel #3
0
void map::apply_light_arc(int x, int y, int angle, float luminance, int wideangle )
{
    if (luminance <= LIGHT_SOURCE_LOCAL) {
        return;
    }

    static bool lit[LIGHTMAP_CACHE_X][LIGHTMAP_CACHE_Y];
    memset(lit, 0, sizeof(lit));

#define lum_mult 3.0

    luminance = luminance * lum_mult;

    int range = LIGHT_RANGE(luminance);
    apply_light_source(x, y, LIGHT_SOURCE_LOCAL, trigdist);

    // Normalise (should work with negative values too)

    const double PI = 3.14159265358979f;
    const double HALFPI = 1.570796326794895f;
    const double wangle = wideangle / 2.0;

    int nangle = angle % 360;

    int endx, endy;
    double rad = PI * (double)nangle / 180;
    calc_ray_end(nangle, range, x, y, &endx, &endy);
    apply_light_ray(lit, x, y, endx, endy , luminance, trigdist);

    int testx, testy;
    calc_ray_end(wangle + nangle, range, x, y, &testx, &testy);

    double wdist = sqrt(double((endx - testx) * (endx - testx) + (endy - testy) * (endy - testy)));
    if(wdist > 0.5) {
        double wstep = ( wangle / ( wdist *
                                    1.42 ) ); // attempt to determine beam density required to cover all squares

        for (double ao = wstep; ao <= wangle; ao += wstep) {
            if ( trigdist ) {
                double fdist = (ao * HALFPI) / wangle;
                double orad = ( PI * ao / 180.0 );
                endx = int( x + ( (double)range - fdist * 2.0) * cos(rad + orad) );
                endy = int( y + ( (double)range - fdist * 2.0) * sin(rad + orad) );
                apply_light_ray(lit, x, y, endx, endy , luminance, true);

                endx = int( x + ( (double)range - fdist * 2.0) * cos(rad - orad) );
                endy = int( y + ( (double)range - fdist * 2.0) * sin(rad - orad) );
                apply_light_ray(lit, x, y, endx, endy , luminance, true);
            } else {
                calc_ray_end(nangle + ao, range, x, y, &endx, &endy);
                apply_light_ray(lit, x, y, endx, endy , luminance, false);
                calc_ray_end(nangle - ao, range, x, y, &endx, &endy);
                apply_light_ray(lit, x, y, endx, endy , luminance, false);
            }
        }
    }
}
Beispiel #4
0
void map::apply_light_arc(int x, int y, int angle, float luminance, int wideangle )
{
    if (luminance <= LIGHT_SOURCE_LOCAL) {
        return;
    }

    bool lit[LIGHTMAP_CACHE_X][LIGHTMAP_CACHE_Y] {};

    constexpr float lum_mult = 3.0f;

    luminance = luminance * lum_mult;

    int range = LIGHT_RANGE(luminance);
    apply_light_source(x, y, LIGHT_SOURCE_LOCAL, trigdist);

    // Normalise (should work with negative values too)
    const double wangle = wideangle / 2.0;

    int nangle = angle % 360;

    int endx, endy;
    double rad = PI * (double)nangle / 180;
    calc_ray_end(nangle, range, x, y, &endx, &endy);
    apply_light_ray(lit, x, y, endx, endy , luminance, trigdist);

    int testx, testy;
    calc_ray_end(wangle + nangle, range, x, y, &testx, &testy);

    const float wdist = hypot(endx - testx, endy - testy);
    if (wdist <= 0.5) {
        return;
    }

    // attempt to determine beam density required to cover all squares
    const double wstep = ( wangle / ( wdist * SQRT_2 ) );

    for (double ao = wstep; ao <= wangle; ao += wstep) {
        if ( trigdist ) {
            double fdist = (ao * HALFPI) / wangle;
            double orad = ( PI * ao / 180.0 );
            endx = int( x + ( (double)range - fdist * 2.0) * cos(rad + orad) );
            endy = int( y + ( (double)range - fdist * 2.0) * sin(rad + orad) );
            apply_light_ray(lit, x, y, endx, endy , luminance, true);

            endx = int( x + ( (double)range - fdist * 2.0) * cos(rad - orad) );
            endy = int( y + ( (double)range - fdist * 2.0) * sin(rad - orad) );
            apply_light_ray(lit, x, y, endx, endy , luminance, true);
        } else {
            calc_ray_end(nangle + ao, range, x, y, &endx, &endy);
            apply_light_ray(lit, x, y, endx, endy , luminance, false);
            calc_ray_end(nangle - ao, range, x, y, &endx, &endy);
            apply_light_ray(lit, x, y, endx, endy , luminance, false);
        }
    }
}
Beispiel #5
0
void map::apply_light_arc( const tripoint &p, int angle, float luminance, int wideangle )
{
    if (luminance <= LIGHT_SOURCE_LOCAL) {
        return;
    }

    bool lit[LIGHTMAP_CACHE_X][LIGHTMAP_CACHE_Y] {};

    apply_light_source( p, LIGHT_SOURCE_LOCAL );

    // Normalise (should work with negative values too)
    const double wangle = wideangle / 2.0;

    int nangle = angle % 360;

    tripoint end;
    double rad = PI * (double)nangle / 180;
    int range = LIGHT_RANGE(luminance);
    calc_ray_end( nangle, range, p, end );
    apply_light_ray(lit, p, end , luminance);

    tripoint test;
    calc_ray_end(wangle + nangle, range, p, test );

    const float wdist = hypot( end.x - test.x, end.y - test.y );
    if (wdist <= 0.5) {
        return;
    }

    // attempt to determine beam density required to cover all squares
    const double wstep = ( wangle / ( wdist * SQRT_2 ) );

    for( double ao = wstep; ao <= wangle; ao += wstep ) {
        if( trigdist ) {
            double fdist = (ao * HALFPI) / wangle;
            double orad = ( PI * ao / 180.0 );
            end.x = int( p.x + ( (double)range - fdist * 2.0) * cos(rad + orad) );
            end.y = int( p.y + ( (double)range - fdist * 2.0) * sin(rad + orad) );
            apply_light_ray( lit, p, end, luminance );

            end.x = int( p.x + ( (double)range - fdist * 2.0) * cos(rad - orad) );
            end.y = int( p.y + ( (double)range - fdist * 2.0) * sin(rad - orad) );
            apply_light_ray( lit, p, end, luminance );
        } else {
            calc_ray_end( nangle + ao, range, p, end );
            apply_light_ray( lit, p, end, luminance );
            calc_ray_end( nangle - ao, range, p, end );
            apply_light_ray( lit, p, end, luminance );
        }
    }
}
Beispiel #6
0
void map::generate_lightmap()
{
    memset(lm, 0, sizeof(lm));
    memset(sm, 0, sizeof(sm));

    /* Bulk light sources wastefully cast rays into neighbors; a burning hospital can produce
         significant slowdown, so for stuff like fire and lava:
     * Step 1: Store the position and luminance in buffer via add_light_source, for efficient
         checking of neighbors.
     * Step 2: After everything else, iterate buffer and apply_light_source only in non-redundant
         directions
     * Step 3: Profit!
     */
    memset(light_source_buffer, 0, sizeof(light_source_buffer));

    constexpr int dir_x[] = {  0, -1 , 1, 0 };   //    [0]
    constexpr int dir_y[] = { -1,  0 , 0, 1 };   // [1][X][2]
    constexpr int dir_d[] = { 180, 270, 0, 90 }; //    [3]

    const bool  u_is_inside    = !is_outside(g->u.posx(), g->u.posy());
    const float natural_light  = g->natural_light_level();
    const float hl             = natural_light / 2;

    if (natural_light > LIGHT_SOURCE_BRIGHT) {
        // Apply sunlight, first light source so just assign
        for (int sx = DAYLIGHT_LEVEL - hl; sx < LIGHTMAP_CACHE_X - hl; ++sx) {
            for (int sy = DAYLIGHT_LEVEL - hl; sy < LIGHTMAP_CACHE_Y - hl; ++sy) {
                // In bright light indoor light exists to some degree
                if (!is_outside(sx, sy)) {
                    lm[sx][sy] = LIGHT_AMBIENT_LOW;
                } else if (g->u.posx() == sx && g->u.posy() == sy ) {
                    //Only apply daylight on square where player is standing to avoid flooding
                    // the lightmap  when in less than total sunlight.
                    lm[sx][sy] = natural_light;
                }
            }
        }
    }

    apply_character_light( g->u );
    for( auto &n : g->active_npc ) {
        apply_character_light( *n );
    }

    // LIGHTMAP_CACHE_X = MAPSIZE * SEEX
    // LIGHTMAP_CACHE_Y = MAPSIZE * SEEY
    // Traverse the submaps in order
    for (int smx = 0; smx < my_MAPSIZE; ++smx) {
        for (int smy = 0; smy < my_MAPSIZE; ++smy) {
            auto const cur_submap = get_submap_at_grid( smx, smy );

            for (int sx = 0; sx < SEEX; ++sx) {
                for (int sy = 0; sy < SEEY; ++sy) {
                    const int x = sx + smx * SEEX;
                    const int y = sy + smy * SEEY;
                    // When underground natural_light is 0, if this changes we need to revisit
                    // Only apply this whole thing if the player is inside,
                    // buildings will be shadowed when outside looking in.
                    if (natural_light > LIGHT_SOURCE_BRIGHT && u_is_inside && !is_outside(x, y)) {
                        // Apply light sources for external/internal divide
                        for(int i = 0; i < 4; ++i) {
                            if (INBOUNDS(x + dir_x[i], y + dir_y[i]) &&
                                is_outside(x + dir_x[i], y + dir_y[i])) {
                                lm[x][y] = natural_light;

                                if (light_transparency(x, y) > LIGHT_TRANSPARENCY_SOLID) {
                                    apply_light_arc(x, y, dir_d[i], natural_light);
                                }
                            }
                        }
                    }

                    if (cur_submap->lum[sx][sy]) {
                        auto items = i_at(x, y);
                        add_light_from_items(x, y, items.begin(), items.end());
                    }

                    const ter_id terrain = cur_submap->ter[sx][sy];
                    if (terrain == t_lava) {
                        add_light_source(x, y, 50 );
                    } else if (terrain == t_console) {
                        add_light_source(x, y, 3 );
                    } else if (terrain == t_utility_light) {
                        add_light_source(x, y, 35 );
                    }

                    for( auto &fld : cur_submap->fld[sx][sy] ) {
                        const field_entry *cur = &fld.second;
                        // TODO: [lightmap] Attach light brightness to fields
                        switch(cur->getFieldType()) {
                        case fd_fire:
                            if (3 == cur->getFieldDensity()) {
                                add_light_source(x, y, 160);
                            } else if (2 == cur->getFieldDensity()) {
                                add_light_source(x, y, 60);
                            } else {
                                add_light_source(x, y, 16);
                            }
                            break;
                        case fd_fire_vent:
                        case fd_flame_burst:
                            add_light_source(x, y, 8);
                            break;
                        case fd_electricity:
                        case fd_plasma:
                            if (3 == cur->getFieldDensity()) {
                                add_light_source(x, y, 8);
                            } else if (2 == cur->getFieldDensity()) {
                                add_light_source(x, y, 1);
                            } else {
                                apply_light_source(x, y, LIGHT_SOURCE_LOCAL,
                                                   trigdist);    // kinda a hack as the square will still get marked
                            }
                            break;
                        case fd_incendiary:
                            if (3 == cur->getFieldDensity()) {
                                add_light_source(x, y, 30);
                            } else if (2 == cur->getFieldDensity()) {
                                add_light_source(x, y, 16);
                            } else {
                                add_light_source(x, y, 8);
                            }
                            break;
                        case fd_laser:
                            apply_light_source(x, y, 1, trigdist);
                            break;
                        case fd_spotlight:
                            add_light_source(x, y, 20);
                            break;
                        case fd_dazzling:
                            add_light_source(x, y, 2);
                            break;
                        default:
                            //Suppress warnings
                            break;
                        }
                    }
                }
            }
        }
    }

    for (size_t i = 0; i < g->num_zombies(); ++i) {
        auto &critter = g->zombie(i);
        if(critter.is_hallucination()) {
            continue;
        }
        int mx = critter.posx();
        int my = critter.posy();
        if (INBOUNDS(mx, my)) {
            if (critter.has_effect("onfire")) {
                apply_light_source(mx, my, 3, trigdist);
            }
            // TODO: [lightmap] Attach natural light brightness to creatures
            // TODO: [lightmap] Allow creatures to have light attacks (ie: eyebot)
            // TODO: [lightmap] Allow creatures to have facing and arc lights
            if (critter.type->luminance > 0) {
                apply_light_source(mx, my, critter.type->luminance, trigdist);
            }
        }
    }

    // Apply any vehicle light sources
    VehicleList vehs = get_vehicles();
    for( auto &vv : vehs ) {
        vehicle *v = vv.v;
        if(v->lights_on) {
            int dir = v->face.dir();
            float veh_luminance = 0.0;
            float iteration = 1.0;
            std::vector<int> light_indices = v->all_parts_with_feature(VPFLAG_CONE_LIGHT);
            for( auto &light_indice : light_indices ) {
                veh_luminance += ( v->part_info( light_indice ).bonus / iteration );
                iteration = iteration * 1.1;
            }
            if (veh_luminance > LL_LIT) {
                for( auto &light_indice : light_indices ) {
                    int px = vv.x + v->parts[light_indice].precalc[0].x;
                    int py = vv.y + v->parts[light_indice].precalc[0].y;
                    if(INBOUNDS(px, py)) {
                        add_light_source(px, py, SQRT_2); // Add a little surrounding light
                        apply_light_arc( px, py, dir + v->parts[light_indice].direction,
                                         veh_luminance, 45 );
                    }
                }
            }
        }
        if(v->overhead_lights_on) {
            std::vector<int> light_indices = v->all_parts_with_feature(VPFLAG_CIRCLE_LIGHT);
            for( auto &light_indice : light_indices ) {
                if( ( calendar::turn % 2 &&
                      v->part_info( light_indice ).has_flag( VPFLAG_ODDTURN ) ) ||
                    ( !( calendar::turn % 2 ) &&
                      v->part_info( light_indice ).has_flag( VPFLAG_EVENTURN ) ) ||
                    ( !v->part_info( light_indice ).has_flag( VPFLAG_EVENTURN ) &&
                      !v->part_info( light_indice ).has_flag( VPFLAG_ODDTURN ) ) ) {
                    int px = vv.x + v->parts[light_indice].precalc[0].x;
                    int py = vv.y + v->parts[light_indice].precalc[0].y;
                    if(INBOUNDS(px, py)) {
                        add_light_source( px, py, v->part_info( light_indice ).bonus );
                    }
                }
            }
        }
        // why reinvent the [lightmap] wheel
        if(v->dome_lights_on) {
            std::vector<int> light_indices = v->all_parts_with_feature(VPFLAG_DOME_LIGHT);
            for( auto &light_indice : light_indices ) {
                int px = vv.x + v->parts[light_indice].precalc[0].x;
                int py = vv.y + v->parts[light_indice].precalc[0].y;
                if(INBOUNDS(px, py)) {
                    add_light_source( px, py, v->part_info( light_indice ).bonus );
                }
            }
        }
        if(v->aisle_lights_on) {
            std::vector<int> light_indices = v->all_parts_with_feature(VPFLAG_AISLE_LIGHT);
            for( auto &light_indice : light_indices ) {
                int px = vv.x + v->parts[light_indice].precalc[0].x;
                int py = vv.y + v->parts[light_indice].precalc[0].y;
                if(INBOUNDS(px, py)) {
                    add_light_source( px, py, v->part_info( light_indice ).bonus );
                }
            }
        }
        if(v->has_atomic_lights) {
            // atomic light is always on
            std::vector<int> light_indices = v->all_parts_with_feature(VPFLAG_ATOMIC_LIGHT);
            for( auto &light_indice : light_indices ) {
                int px = vv.x + v->parts[light_indice].precalc[0].x;
                int py = vv.y + v->parts[light_indice].precalc[0].y;
                if(INBOUNDS(px, py)) {
                    add_light_source( px, py, v->part_info( light_indice ).bonus );
                }
            }
        }
        for( size_t p = 0; p < v->parts.size(); ++p ) {
            int px = vv.x + v->parts[p].precalc[0].x;
            int py = vv.y + v->parts[p].precalc[0].y;
            if( !INBOUNDS( px, py ) ) {
                continue;
            }
            if( v->part_flag( p, VPFLAG_CARGO ) && !v->part_flag( p, "COVERED" ) ) {
                add_light_from_items( px, py, v->get_items(p).begin(), v->get_items(p).end() );
            }
        }
    }

    /* Now that we have position and intensity of all bulk light sources, apply_ them
      This may seem like extra work, but take a 12x12 raging inferno:
        unbuffered: (12^2)*(160*4) = apply_light_ray x 92160
        buffered:   (12*4)*(160)   = apply_light_ray x 7680
    */
    for(int sx = 0; sx < LIGHTMAP_CACHE_X; ++sx) {
        for(int sy = 0; sy < LIGHTMAP_CACHE_Y; ++sy) {
            if ( light_source_buffer[sx][sy] > 0. ) {
                apply_light_source(sx, sy, light_source_buffer[sx][sy],
                                   ( trigdist && light_source_buffer[sx][sy] > 3. ) );
            }
        }
    }


    if (g->u.has_active_bionic("bio_night") ) {
        for(int sx = 0; sx < LIGHTMAP_CACHE_X; ++sx) {
            for(int sy = 0; sy < LIGHTMAP_CACHE_Y; ++sy) {
                if (rl_dist(sx, sy, g->u.posx(), g->u.posy()) < 15) {
                    lm[sx][sy] = 0;
                }
            }
        }
    }
}
Beispiel #7
0
void map::generate_lightmap()
{
    memset(lm, 0, sizeof(lm));
    memset(sm, 0, sizeof(sm));

    /* Bulk light sources wastefully cast rays into neighbors; a burning hospital can produce
         significant slowdown, so for stuff like fire and lava:
     * Step 1: Store the position and luminance in buffer via add_light_source, for efficient
         checking of neighbors.
     * Step 2: After everything else, iterate buffer and apply_light_source only in non-redundant
         directions
     * Step 3: Profit!
     */
    memset(light_source_buffer, 0, sizeof(light_source_buffer));


    const int dir_x[] = { 1, 0 , -1,  0 };
    const int dir_y[] = { 0, 1 ,  0, -1 };
    const int dir_d[] = { 180, 270, 0, 90 };
    const float held_luminance = g->u.active_light();
    const float natural_light = g->natural_light_level();

    if (natural_light > LIGHT_SOURCE_BRIGHT) {
        // Apply sunlight, first light source so just assign
        for(int sx = DAYLIGHT_LEVEL - (natural_light / 2);
            sx < LIGHTMAP_CACHE_X - (natural_light / 2); ++sx) {
            for(int sy = DAYLIGHT_LEVEL - (natural_light / 2);
                sy < LIGHTMAP_CACHE_Y - (natural_light / 2); ++sy) {
                // In bright light indoor light exists to some degree
                if (!is_outside(sx, sy)) {
                    lm[sx][sy] = LIGHT_AMBIENT_LOW;
                } else if (g->u.posx == sx && g->u.posy == sy ) {
                    //Only apply daylight on square where player is standing to avoid flooding
                    // the lightmap  when in less than total sunlight.
                    lm[sx][sy] = natural_light;
                }
            }
        }
    }

    // Apply player light sources
    if (held_luminance > LIGHT_AMBIENT_LOW) {
        apply_light_source(g->u.posx, g->u.posy, held_luminance, trigdist);
    }
    for(int sx = 0; sx < LIGHTMAP_CACHE_X; ++sx) {
        for(int sy = 0; sy < LIGHTMAP_CACHE_Y; ++sy) {
            const ter_id terrain = ter(sx, sy);
            const std::vector<item> &items = i_at(sx, sy);
            field &current_field = field_at(sx, sy);
            // When underground natural_light is 0, if this changes we need to revisit
            // Only apply this whole thing if the player is inside,
            // buildings will be shadowed when outside looking in.
            if (natural_light > LIGHT_AMBIENT_LOW && !is_outside(g->u.posx, g->u.posy) ) {
                if (!is_outside(sx, sy)) {
                    // Apply light sources for external/internal divide
                    for(int i = 0; i < 4; ++i) {
                        if (INBOUNDS(sx + dir_x[i], sy + dir_y[i]) &&
                            is_outside(sx + dir_x[i], sy + dir_y[i])) {
                            lm[sx][sy] = natural_light;

                            if (light_transparency(sx, sy) > LIGHT_TRANSPARENCY_SOLID) {
                                apply_light_arc(sx, sy, dir_d[i], natural_light);
                            }
                        }
                    }
                }
            }
            for( std::vector<item>::const_iterator itm = items.begin(); itm != items.end(); ++itm ) {

                float ilum = 0.0; // brightness
                int iwidth = 0; // 0-360 degrees. 0 is a circular light_source
                int idir = 0;   // otherwise, it's a light_arc pointed in this direction
                if ( itm->getlight(ilum, iwidth, idir ) ) {
                    if ( iwidth > 0 ) {
                        apply_light_arc( sx, sy, idir, ilum, iwidth );
                    } else {
                        add_light_source(sx, sy, ilum);
                    }
                }
            }
            if(terrain == t_lava) {
                add_light_source(sx, sy, 50 );
            }

            if(terrain == t_console) {
                add_light_source(sx, sy, 3 );
            }

            if(terrain == t_emergency_light) {
                add_light_source(sx, sy, 3 );
            }

            if(terrain == t_utility_light) {
                add_light_source(sx, sy, 35 );
            }

            field_entry *cur = NULL;
            for(std::map<field_id, field_entry *>::iterator field_list_it = current_field.getFieldStart();
                field_list_it != current_field.getFieldEnd(); ++field_list_it) {
                cur = field_list_it->second;

                if(cur == NULL) {
                    continue;
                }
                // TODO: [lightmap] Attach light brightness to fields
                switch(cur->getFieldType()) {
                case fd_fire:
                    if (3 == cur->getFieldDensity()) {
                        add_light_source(sx, sy, 160);
                    } else if (2 == cur->getFieldDensity()) {
                        add_light_source(sx, sy, 60);
                    } else {
                        add_light_source(sx, sy, 16);
                    }
                    break;
                case fd_fire_vent:
                case fd_flame_burst:
                    add_light_source(sx, sy, 8);
                    break;
                case fd_electricity:
                case fd_plasma:
                    if (3 == cur->getFieldDensity()) {
                        add_light_source(sx, sy, 8);
                    } else if (2 == cur->getFieldDensity()) {
                        add_light_source(sx, sy, 1);
                    } else {
                        apply_light_source(sx, sy, LIGHT_SOURCE_LOCAL,
                                           trigdist);    // kinda a hack as the square will still get marked
                    }
                    break;
                case fd_incendiary:
                    if (3 == cur->getFieldDensity()) {
                        add_light_source(sx, sy, 30);
                    } else if (2 == cur->getFieldDensity()) {
                        add_light_source(sx, sy, 16);
                    } else {
                        add_light_source(sx, sy, 8);
                    }
                    break;
                case fd_laser:
                    apply_light_source(sx, sy, 1, trigdist);
                    break;
                case fd_spotlight:
                    add_light_source(sx, sy, 20);
                    break;
                case fd_dazzling:
                    add_light_source(sx, sy, 2);
                    break;
                default:
                    //Suppress warnings
                    break;
                }
            }
        }
    }

    for (size_t i = 0; i < g->num_zombies(); ++i) {
        int mx = g->zombie(i).posx();
        int my = g->zombie(i).posy();
        if (INBOUNDS(mx, my)) {
            if (g->zombie(i).has_effect("onfire")) {
                apply_light_source(mx, my, 3, trigdist);
            }
            // TODO: [lightmap] Attach natural light brightness to creatures
            // TODO: [lightmap] Allow creatures to have light attacks (ie: eyebot)
            // TODO: [lightmap] Allow creatures to have facing and arc lights
            if (g->zombie(i).type->luminance > 0) {
                apply_light_source(mx, my, g->zombie(i).type->luminance, trigdist);
            }
        }
    }

    // Apply any vehicle light sources
    VehicleList vehs = get_vehicles();
    for( size_t v = 0; v < vehs.size(); ++v ) {
        if(vehs[v].v->lights_on) {
            int dir = vehs[v].v->face.dir();
            float veh_luminance = 0.0;
            float iteration = 1.0;
            std::vector<int> light_indices = vehs[v].v->all_parts_with_feature(VPFLAG_CONE_LIGHT);
            for (std::vector<int>::iterator part = light_indices.begin();
                 part != light_indices.end(); ++part) {
                veh_luminance += ( vehs[v].v->part_info(*part).bonus / iteration );
                iteration = iteration * 1.1;
            }
            if (veh_luminance > LL_LIT) {
                for (std::vector<int>::iterator part = light_indices.begin();
                     part != light_indices.end(); ++part) {
                    int px = vehs[v].x + vehs[v].v->parts[*part].precalc_dx[0];
                    int py = vehs[v].y + vehs[v].v->parts[*part].precalc_dy[0];
                    if(INBOUNDS(px, py)) {
                        apply_light_arc(px, py, dir + vehs[v].v->parts[*part].direction, veh_luminance, 45);
                    }
                }
            }
        }
        if(vehs[v].v->overhead_lights_on) {
            std::vector<int> light_indices = vehs[v].v->all_parts_with_feature(VPFLAG_CIRCLE_LIGHT);
            for (std::vector<int>::iterator part = light_indices.begin();
                 part != light_indices.end(); ++part) {
                if((calendar::turn % 2 && vehs[v].v->part_info(*part).has_flag(VPFLAG_ODDTURN)) ||
                   (!(calendar::turn % 2) && vehs[v].v->part_info(*part).has_flag(VPFLAG_EVENTURN)) ||
                   (!vehs[v].v->part_info(*part).has_flag(VPFLAG_EVENTURN) &&
                    !vehs[v].v->part_info(*part).has_flag(VPFLAG_ODDTURN))) {
                    int px = vehs[v].x + vehs[v].v->parts[*part].precalc_dx[0];
                    int py = vehs[v].y + vehs[v].v->parts[*part].precalc_dy[0];
                    if(INBOUNDS(px, py)) {
                        add_light_source( px, py, vehs[v].v->part_info(*part).bonus );
                    }
                }
            }
        }
    }

    /* Now that we have position and intensity of all bulk light sources, apply_ them
      This may seem like extra work, but take a 12x12 raging inferno:
        unbuffered: (12^2)*(160*4) = apply_light_ray x 92160
        buffered:   (12*4)*(160)   = apply_light_ray x 7680
    */
    for(int sx = 0; sx < LIGHTMAP_CACHE_X; ++sx) {
        for(int sy = 0; sy < LIGHTMAP_CACHE_Y; ++sy) {
            if ( light_source_buffer[sx][sy] > 0. ) {
                apply_light_source(sx, sy, light_source_buffer[sx][sy],
                                   ( trigdist && light_source_buffer[sx][sy] > 3. ) );
            }
        }
    }


    if (g->u.has_active_bionic("bio_night") ) {
        for(int sx = 0; sx < LIGHTMAP_CACHE_X; ++sx) {
            for(int sy = 0; sy < LIGHTMAP_CACHE_Y; ++sy) {
                if (rl_dist(sx, sy, g->u.posx, g->u.posy) < 15) {
                    lm[sx][sy] = 0;
                }
            }
        }
    }
}
Beispiel #8
0
/*
 * Adds the effect of the given light over the given intersection.
 *
 * light: Light that is being applied.
 * inter: Intersection over which the light is being applied.
 * normal_vec:  Normal vector of the intersection point. It is passed by as a
 *              parameter for optimization purposes.
 * rev_dir_vec: Reverse vector of the direction of the ray that comes from the
 *              eye. It is passed by as a parameter for optimization purposes.
 * all_lights_color: Accumulated amount of light sources effect. The effect of
 *              the given light is added to this total.
 * all_lights_color: Accumulated amount of the specular light effect. The
 *              specular effect of the given light is added to this total.
 * conf: Configuration of the scene.
 */
void apply_light_source(Light light,
                        Intersection inter,
                        Vector normal_vec,
                        Vector rev_dir_vec,
                        Color *all_lights_color,
                        long double *all_spec_light,
                        SceneConfig conf)
{
    Vector light_vec;
    long double light_distance, illum_cos, att_factor, spec_cos;
    Color light_filter;
    Intersection* shadow_inter;
    int shadow_i, shadow_inter_length;
    Object shadow_obj;

    // Find the vector that points from the intersection point to the light
    // source, and normalize it
    light_vec = subtract_vectors(light.anchor, inter.posn);
    light_distance = normalize_vector(&light_vec);
    // We check for any object making a shadow from that light
    light_filter = (Color){ .red = 1.0, .green = 1.0, .blue = 1.0 };;
    shadow_inter = get_intersections(inter.posn, light_vec, &shadow_inter_length, conf);
    // If the intersection is beyond the light source, we ignore it
    if(shadow_inter)
    {   // Object(s) is/are actually behind the light
        for(shadow_i = 0; shadow_i < shadow_inter_length && !is_color_empty(light_filter); shadow_i++)
        {
            if(shadow_inter[shadow_i].distance < light_distance)
            {
                shadow_obj = shadow_inter[shadow_i].obj;
                if(shadow_obj.translucency_material)
                {
                    light_filter = multiply_color(shadow_obj.translucency_material, multiply_colors(light_filter, shadow_obj.color));
                }
                else
                {
                    light_filter = get_empty_color();
                }
            }

        }
        if(!is_color_empty(light_filter))
        {
            free(shadow_inter);
            shadow_inter = NULL;
        }
    }
    // If there aren't any shadows
    if(!shadow_inter)
    {
        illum_cos = do_dot_product(normal_vec, light_vec);
        // We only take it into account if the angle is lower than 90 degrees
        if(illum_cos > 0)
        {
            Vector light_mirror_vec = subtract_vectors(multiply_vector(2 * illum_cos, normal_vec), light_vec);
            // Attenuation factor, reduces the light energy depending on the distance
            att_factor = get_attenuation_factor(light, light_distance);
            spec_cos = do_dot_product(rev_dir_vec, light_mirror_vec);
            // We add the light source effect
            light_filter = multiply_color(illum_cos * inter.obj.light_material * att_factor, light_filter);
            *all_lights_color = add_colors(*all_lights_color, multiply_colors(light_filter, light.color));
            // The specular light, is the white stain on the objects
            if(spec_cos > 0)
            {
                *all_spec_light += pow(spec_cos * inter.obj.specular_material * att_factor, inter.obj.specular_pow);
            }
        }
    }
    else free(shadow_inter);
}

/*
 * Gets the color of the intersection by calculating light intensity,
 * (which includes specular light, shadows, transparency, etc)
 *
 * light: Light for which the attenuation factor is calculated.
 * distance: Distance between the light and an illuminated spot.
 * mirror_level: Current level of reflection.
 * conf: Configuration of the scene.
 */
Color get_intersection_color(Vector eye,
                             Vector dir_vec,
                             Intersection *inter_list,
                             int inter_length,
                             int mirror_level,
                             int transparency_level,
                             SceneConfig conf)
{
    Intersection inter;
    int light_index;
    long double spec_light_factor, mirror_factor, transparency_factor;
    Vector normal_vec, rev_dir_vec, reflection_vec;
    Light light;
    Color all_lights_color, color_found, reflection_color,
          transparency_color, final_color;

    inter = inter_list[transparency_level];
    // Light intensity
    all_lights_color = (Color){ .red = 0.0, .green = 0.0, .blue = 0.0 };
    // Specular light intensity
    spec_light_factor = 0.0;
    normal_vec = get_normal_vector(&inter);
    // Pick up the normal vector that is pointing to the eye
    if(do_dot_product(normal_vec, dir_vec) > 0)
        normal_vec = multiply_vector(-1, normal_vec);
    // Initialize reverse direction vector for mirrors and specular light
    rev_dir_vec = multiply_vector(-1, dir_vec);
    for(light_index = 0; light_index < conf.lights_length; light_index++)
    {
        light = conf.lights[light_index];
        apply_light_source(light, inter, normal_vec, rev_dir_vec, &all_lights_color, &spec_light_factor, conf);
    }
    // We add the environmental light of the scene
    all_lights_color = add_colors(all_lights_color, multiply_color(inter.obj.light_ambiental, conf.environment_light));
    if(spec_light_factor > 1.0)
        spec_light_factor = 1.0;
    color_found = multiply_colors(all_lights_color, inter.obj.color);
    // Specular light gives a color between enlightened color and the light color.
    color_found.red += (1 - color_found.red) * spec_light_factor;
    color_found.green += (1 - color_found.green) * spec_light_factor;
    color_found.blue += (1 - color_found.blue) * spec_light_factor;
    // Get transparency color
    transparency_factor = inter.obj.transparency_material;
    if (transparency_level < conf.max_transparency_level &&
        transparency_factor > 0.0)
    {
        if(transparency_level + 1 < inter_length)
        {
            transparency_color = get_intersection_color(eye,dir_vec,inter_list,inter_length,0,transparency_level+1, conf);
        }
        else
        {
            transparency_color = conf.background;
        }
    }
    else
    {
        transparency_factor = 0.0;
        transparency_color = get_empty_color();
    }
    // Get reflection color
    mirror_factor = inter.obj.mirror_material;
    if (mirror_level < conf.max_mirror_level &&
        mirror_factor > 0.0)
    {
        reflection_vec = subtract_vectors(multiply_vector(2 * do_dot_product(normal_vec, rev_dir_vec), normal_vec), rev_dir_vec);
        reflection_color = get_color(inter.posn, reflection_vec, mirror_level + 1, conf);
    }
    else
    {
        mirror_factor = 0;
        reflection_color = get_empty_color();
    }
    // Calculate final color
    transparency_color = multiply_color(transparency_factor, transparency_color);
    reflection_color = multiply_color((1.0-transparency_factor) * mirror_factor, reflection_color);
    color_found = multiply_color((1.0-transparency_factor) * (1.0-mirror_factor), color_found);
    final_color = add_colors(transparency_color, add_colors(reflection_color, color_found));
    return final_color;
}

/*
 * Returns the color that is seen from the position 'eye' when looking at the
 * tridimensional scene towards the direction 'dir_vec'.
 *
 * eye: Position from which the scene is seen.
 * dir_vec: Direction at which the eye is looking. This vector must be normalized.
 * mirror_level: Current level of reflection.
 * conf: Configuration of the scene.
 */
Color get_color(Vector eye, Vector dir_vec, int mirror_level, SceneConfig conf)
{
	Intersection *inter_list;
	Color color;
	// Get intersections on the given direction. Intersections are ordered from the nearest to the farthest.
	int inter_list_length;
	inter_list = get_intersections(eye, dir_vec, &inter_list_length, conf);
	// If we don't find an intersection we return the background, otherwise we check for the intersections's color.
	if (!inter_list) return conf.background;
	color = get_intersection_color(eye, dir_vec, inter_list, inter_list_length, mirror_level, 0, conf);
	free(inter_list);
	return color;
}
Beispiel #9
0
void map::generate_lightmap(game* g)
{
 memset(lm, 0, sizeof(lm));
 memset(sm, 0, sizeof(sm));

 const int dir_x[] = { 1, 0 , -1,  0 };
 const int dir_y[] = { 0, 1 ,  0, -1 };
 const int dir_d[] = { 180, 270, 0, 90 };
 const float luminance = g->u.active_light();
 const float natural_light = g->natural_light_level();

 // Daylight vision handling returned back to map due to issues it causes here
 if (natural_light > LIGHT_SOURCE_BRIGHT) {
  // Apply sunlight, first light source so just assign
  for(int sx = 0; sx < LIGHTMAP_CACHE_X; ++sx) {
   for(int sy = 0; sy < LIGHTMAP_CACHE_Y; ++sy) {
    // In bright light indoor light exists to some degree
    if (!g->m.is_outside(sx, sy))
     lm[sx][sy] = LIGHT_AMBIENT_LOW;
   }
  }
 }

 // Apply player light sources
 if (luminance > LIGHT_AMBIENT_LOW)
  apply_light_source(g->u.posx, g->u.posy, luminance);

  for(int sx = 0; sx < LIGHTMAP_CACHE_X; ++sx) {
   for(int sy = 0; sy < LIGHTMAP_CACHE_Y; ++sy) {
    const ter_id terrain = g->m.ter(sx, sy);
    const std::vector<item> items = g->m.i_at(sx, sy);
    const field current_field = g->m.field_at(sx, sy);
    // When underground natural_light is 0, if this changes we need to revisit
    if (natural_light > LIGHT_AMBIENT_LOW) {
     if (!g->m.is_outside(sx, sy)) {
      // Apply light sources for external/internal divide
      for(int i = 0; i < 4; ++i) {
       if (INBOUNDS(sx + dir_x[i], sy + dir_y[i]) &&
           g->m.is_outside(sx + dir_x[i], sy + dir_y[i])) {
        if (INBOUNDS(sx, sy) && g->m.is_outside(0, 0))
         lm[sx][sy] = natural_light;

        if (g->m.light_transparency(sx, sy) > LIGHT_TRANSPARENCY_SOLID)
         apply_light_arc(sx, sy, dir_d[i], natural_light);
       }
      }
     }
    }

    if (items.size() == 1 &&
        items[0].type->id == itm_flashlight_on)
     apply_light_source(sx, sy, 20);

   if(terrain == t_lava)
    apply_light_source(sx, sy, 50);

   if(terrain == t_console)
    apply_light_source(sx, sy, 3);

   if (items.size() == 1 &&
       items[0].type->id == itm_candle_lit)
    apply_light_source(sx, sy, 4);

   if(terrain == t_emergency_light)
    apply_light_source(sx, sy, 3);

   // TODO: [lightmap] Attach light brightness to fields
  switch(current_field.type) {
    case fd_fire:
     if (3 == current_field.density)
      apply_light_source(sx, sy, 160);
     else if (2 == current_field.density)
      apply_light_source(sx, sy, 60);
     else
      apply_light_source(sx, sy, 16);
     break;
    case fd_fire_vent:
    case fd_flame_burst:
     apply_light_source(sx, sy, 8);
     break;
    case fd_electricity:
     if (3 == current_field.density)
      apply_light_source(sx, sy, 8);
     else if (2 == current_field.density)
      apply_light_source(sx, sy, 1);
     else
      apply_light_source(sx, sy, LIGHT_SOURCE_LOCAL);  // kinda a hack as the square will still get marked
     break;
   }
  }
 }

 for (int i = 0; i < g->z.size(); ++i) {
  int mx = g->z[i].posx;
  int my = g->z[i].posy;
  if (INBOUNDS(mx, my)) {
   if (g->z[i].has_effect(ME_ONFIRE)) {
    apply_light_source(mx, my, 3);
   }
   // TODO: [lightmap] Attach natural light brightness to creatures
   // TODO: [lightmap] Allow creatures to have light attacks (ie: eyebot)
   // TODO: [lightmap] Allow creatures to have facing and arc lights
   switch (g->z[i].type->id) {
    case mon_zombie_electric:
     apply_light_source(mx, my, 1);
     break;
    case mon_turret:
     apply_light_source(mx, my, 2);
     break;
    case mon_flaming_eye:
     apply_light_source(mx, my, LIGHT_SOURCE_BRIGHT);
     break;
    case mon_manhack:
     apply_light_source(mx, my, LIGHT_SOURCE_LOCAL);
     break;
   }
  }
 }

 // Apply any vehicle light sources
 VehicleList vehs = g->m.get_vehicles();
 for(int v = 0; v < vehs.size(); ++v) {
  if(vehs[v].v->lights_on) {
   int dir = vehs[v].v->face.dir();
   for (std::vector<int>::iterator part = vehs[v].v->external_parts.begin();
        part != vehs[v].v->external_parts.end(); ++part) {
    int px = vehs[v].x + vehs[v].v->parts[*part].precalc_dx[0];
    int py = vehs[v].y + vehs[v].v->parts[*part].precalc_dy[0];
    if(INBOUNDS(px, py)) {
     int dpart = vehs[v].v->part_with_feature(*part , vpf_light);
     if (dpart >= 0) {
      float luminance = vehs[v].v->part_info(dpart).power;
      if (luminance > LL_LIT) {
        apply_light_arc(px, py, dir, luminance);
      }
     }
    }
   }
  }
 }
}
Beispiel #10
0
void map::generate_lightmap(game* g)
{
 memset(lm, 0, sizeof(lm));
 memset(sm, 0, sizeof(sm));

 const int dir_x[] = { 1, 0 , -1,  0 };
 const int dir_y[] = { 0, 1 ,  0, -1 };
 const int dir_d[] = { 180, 270, 0, 90 };
 const float held_luminance = g->u.active_light();
 const float natural_light = g->natural_light_level();

 // Daylight vision handling returned back to map due to issues it causes here
 if (natural_light > LIGHT_SOURCE_BRIGHT)
 {
     // Apply sunlight, first light source so just assign
     for(int sx = 0; sx < LIGHTMAP_CACHE_X; ++sx)
     {
         for(int sy = 0; sy < LIGHTMAP_CACHE_Y; ++sy)
         {
             // In bright light indoor light exists to some degree
             if (!g->m.is_outside(sx, sy))
             {
                 lm[sx][sy] = LIGHT_AMBIENT_LOW;
             }
             else if (g->u.posx == sx && g->u.posy == sy )
             {
                 //Only apply daylight on square where player is standing to avoid flooding
                 // the lightmap  when in less than total sunlight.
                 lm[sx][sy] = natural_light;
             }
         }
     }
 }

 // Apply player light sources
 if (held_luminance > LIGHT_AMBIENT_LOW)
  apply_light_source(g->u.posx, g->u.posy, held_luminance, trigdist);
  int flood_basalt_check = 0; // does excessive lava need high quality lighting? Nope nope nope nope
  for(int sx = 0; sx < LIGHTMAP_CACHE_X; ++sx) {
   for(int sy = 0; sy < LIGHTMAP_CACHE_Y; ++sy) {
    const ter_id terrain = g->m.ter(sx, sy);
    const std::vector<item> &items = g->m.i_at(sx, sy);
    field &current_field = g->m.field_at(sx, sy);
    // When underground natural_light is 0, if this changes we need to revisit
    if (natural_light > LIGHT_AMBIENT_LOW) {
     if (!g->m.is_outside(sx, sy)) {
      // Apply light sources for external/internal divide
      for(int i = 0; i < 4; ++i) {
       if (INBOUNDS(sx + dir_x[i], sy + dir_y[i]) &&
           g->m.is_outside(sx + dir_x[i], sy + dir_y[i])) {
        if (INBOUNDS(sx, sy) && g->m.is_outside(0, 0))
         lm[sx][sy] = natural_light;

        if (g->m.light_transparency(sx, sy) > LIGHT_TRANSPARENCY_SOLID)
         apply_light_arc(sx, sy, dir_d[i], natural_light);
       }
      }
     }
    }

    for( std::vector<item>::const_iterator itm = items.begin(); itm != items.end(); ++itm )
    {
        if ( itm->has_flag("LIGHT_20")) { apply_light_source(sx, sy, 20, trigdist); }
        if ( itm->has_flag("LIGHT_1")) { apply_light_source(sx, sy, 1, trigdist); }
        if ( itm->has_flag("LIGHT_4")) { apply_light_source(sx, sy, 4, trigdist); }
        if ( itm->has_flag("LIGHT_8")) { apply_light_source(sx, sy, 8, trigdist); }
    }

   if(terrain == t_lava) {
     flood_basalt_check++;
     apply_light_source(sx, sy, 50, trigdist && flood_basalt_check < 512 ); // todo: optimize better
   }

   if(terrain == t_console)
    apply_light_source(sx, sy, 3, false); // 3^2 circle is just silly

   if(terrain == t_emergency_light)
    apply_light_source(sx, sy, 3, false);

   field_entry *cur = NULL;
   for(std::map<field_id, field_entry*>::iterator field_list_it = current_field.getFieldStart(); field_list_it != current_field.getFieldEnd(); ++field_list_it){
       cur = field_list_it->second;

		if(cur == NULL) continue;
   // TODO: [lightmap] Attach light brightness to fields
		switch(cur->getFieldType()) {
    case fd_fire:
		if (3 == cur->getFieldDensity())
      apply_light_source(sx, sy, 160, trigdist);
     else if (2 == cur->getFieldDensity())
      apply_light_source(sx, sy, 60, trigdist);
     else
      apply_light_source(sx, sy, 16, trigdist);
     break;
    case fd_fire_vent:
    case fd_flame_burst:
     apply_light_source(sx, sy, 8, trigdist);
     break;
    case fd_electricity:
    case fd_plasma:
     if (3 == cur->getFieldDensity())
      apply_light_source(sx, sy, 8, trigdist);
     else if (2 == cur->getFieldDensity())
      apply_light_source(sx, sy, 1, trigdist);
     else
      apply_light_source(sx, sy, LIGHT_SOURCE_LOCAL, trigdist);  // kinda a hack as the square will still get marked
     break;
    case fd_laser:
     apply_light_source(sx, sy, 1, trigdist);
     break;
   }
	}
  }
 }

 for (int i = 0; i < g->num_zombies(); ++i) {
  int mx = g->zombie(i).posx();
  int my = g->zombie(i).posy();
  if (INBOUNDS(mx, my)) {
   if (g->zombie(i).has_effect(ME_ONFIRE)) {
     apply_light_source(mx, my, 3, trigdist);
   }
   // TODO: [lightmap] Attach natural light brightness to creatures
   // TODO: [lightmap] Allow creatures to have light attacks (ie: eyebot)
   // TODO: [lightmap] Allow creatures to have facing and arc lights
   switch (g->zombie(i).type->id) {
    case mon_zombie_electric:
     apply_light_source(mx, my, 1, trigdist);
     break;
    case mon_turret:
     apply_light_source(mx, my, 2, trigdist);
     break;
    case mon_flaming_eye:
     apply_light_source(mx, my, LIGHT_SOURCE_BRIGHT, trigdist);
     break;
    case mon_manhack:
     apply_light_source(mx, my, LIGHT_SOURCE_LOCAL, trigdist);
     break;
   }
  }
 }

 // Apply any vehicle light sources
 VehicleList vehs = g->m.get_vehicles();
 for(int v = 0; v < vehs.size(); ++v) {
   if(vehs[v].v->lights_on) {
     int dir = vehs[v].v->face.dir();
     float veh_luminance=0.0;
     float iteration=1.0;
     for (std::vector<int>::iterator part = vehs[v].v->external_parts.begin();
          part != vehs[v].v->external_parts.end(); ++part) {
         int dpart = vehs[v].v->part_with_feature(*part , "LIGHT");
         if (dpart >= 0) {
             veh_luminance += ( vehs[v].v->part_info(dpart).power / iteration );
             iteration=iteration * 1.1;
         }
     }
     if (veh_luminance > LL_LIT) {
       for (std::vector<int>::iterator part = vehs[v].v->external_parts.begin();
            part != vehs[v].v->external_parts.end(); ++part) {
         int px = vehs[v].x + vehs[v].v->parts[*part].precalc_dx[0];
         int py = vehs[v].y + vehs[v].v->parts[*part].precalc_dy[0];
         if(INBOUNDS(px, py)) {
           int dpart = vehs[v].v->part_with_feature(*part , "LIGHT");

           if (dpart >= 0) {
             apply_light_arc(px, py, dir + vehs[v].v->parts[dpart].direction, veh_luminance, 45);
           }
         }
       }
     }
   }
 }
if (g->u.has_active_bionic("bio_night") ) {
   for(int sx = 0; sx < LIGHTMAP_CACHE_X; ++sx)
   {
      for(int sy = 0; sy < LIGHTMAP_CACHE_Y; ++sy)
      {
          if (rl_dist(sx, sy, g->u.posx, g->u.posy) < 15)
          {
              lm[sx][sy] = 0;
          }
      }
   }
  }
}
Beispiel #11
0
void map::generate_lightmap( const int zlev )
{
    auto &map_cache = get_cache( zlev );
    auto &lm = map_cache.lm;
    auto &sm = map_cache.sm;
    auto &outside_cache = map_cache.outside_cache;
    std::memset(lm, 0, sizeof(lm));
    std::memset(sm, 0, sizeof(sm));

    /* Bulk light sources wastefully cast rays into neighbors; a burning hospital can produce
         significant slowdown, so for stuff like fire and lava:
     * Step 1: Store the position and luminance in buffer via add_light_source, for efficient
         checking of neighbors.
     * Step 2: After everything else, iterate buffer and apply_light_source only in non-redundant
         directions
     * Step 3: ????
     * Step 4: Profit!
     */
    auto &light_source_buffer = map_cache.light_source_buffer;
    std::memset(light_source_buffer, 0, sizeof(light_source_buffer));

    constexpr int dir_x[] = {  0, -1 , 1, 0 };   //    [0]
    constexpr int dir_y[] = { -1,  0 , 0, 1 };   // [1][X][2]
    constexpr int dir_d[] = { 90, 0, 180, 270 }; //    [3]

    const float natural_light  = g->natural_light_level( zlev );
    const float inside_light = (natural_light > LIGHT_SOURCE_BRIGHT) ?
        LIGHT_AMBIENT_LOW + 1.0 : LIGHT_AMBIENT_MINIMAL;
    // Apply sunlight, first light source so just assign
    for( int sx = 0; sx < LIGHTMAP_CACHE_X; ++sx ) {
        for( int sy = 0; sy < LIGHTMAP_CACHE_Y; ++sy ) {
            // In bright light indoor light exists to some degree
            if( !outside_cache[sx][sy] ) {
                lm[sx][sy] = inside_light;
            } else {
                lm[sx][sy] = natural_light;
            }
        }
    }

    apply_character_light( g->u );
    for( auto &n : g->active_npc ) {
        apply_character_light( *n );
    }

    // Traverse the submaps in order
    for (int smx = 0; smx < my_MAPSIZE; ++smx) {
        for (int smy = 0; smy < my_MAPSIZE; ++smy) {
            auto const cur_submap = get_submap_at_grid( smx, smy, zlev );

            for (int sx = 0; sx < SEEX; ++sx) {
                for (int sy = 0; sy < SEEY; ++sy) {
                    const int x = sx + smx * SEEX;
                    const int y = sy + smy * SEEY;
                    const tripoint p( x, y, zlev );
                    // Project light into any openings into buildings.
                    if (natural_light > LIGHT_SOURCE_BRIGHT && !outside_cache[p.x][p.y]) {
                        // Apply light sources for external/internal divide
                        for(int i = 0; i < 4; ++i) {
                            if (INBOUNDS(p.x + dir_x[i], p.y + dir_y[i]) &&
                                outside_cache[p.x + dir_x[i]][p.y + dir_y[i]]) {
                                lm[p.x][p.y] = natural_light;

                                if (light_transparency( p ) > LIGHT_TRANSPARENCY_SOLID) {
                                    apply_directional_light( p, dir_d[i], natural_light );
                                }
                            }
                        }
                    }

                    if( cur_submap->lum[sx][sy] && has_items( p ) ) {
                        auto items = i_at( p );
                        add_light_from_items( p, items.begin(), items.end() );
                    }

                    const ter_id terrain = cur_submap->ter[sx][sy];
                    if (terrain == t_lava) {
                        add_light_source( p, 50 );
                    } else if (terrain == t_console) {
                        add_light_source( p, 10 );
                    } else if (terrain == t_utility_light) {
                        add_light_source( p, 240 );
                    }

                    for( auto &fld : cur_submap->fld[sx][sy] ) {
                        const field_entry *cur = &fld.second;
                        // TODO: [lightmap] Attach light brightness to fields
                        switch(cur->getFieldType()) {
                        case fd_fire:
                            if (3 == cur->getFieldDensity()) {
                                add_light_source( p, 160 );
                            } else if (2 == cur->getFieldDensity()) {
                                add_light_source( p, 60 );
                            } else {
                                add_light_source( p, 20 );
                            }
                            break;
                        case fd_fire_vent:
                        case fd_flame_burst:
                            add_light_source( p, 20 );
                            break;
                        case fd_electricity:
                        case fd_plasma:
                            if (3 == cur->getFieldDensity()) {
                                add_light_source( p, 20 );
                            } else if (2 == cur->getFieldDensity()) {
                                add_light_source( p, 4 );
                            } else {
                                // Kinda a hack as the square will still get marked.
                                apply_light_source( p, LIGHT_SOURCE_LOCAL );
                            }
                            break;
                        case fd_incendiary:
                            if (3 == cur->getFieldDensity()) {
                                add_light_source( p, 160 );
                            } else if (2 == cur->getFieldDensity()) {
                                add_light_source( p, 60 );
                            } else {
                                add_light_source( p, 20 );
                            }
                            break;
                        case fd_laser:
                            apply_light_source( p, 4 );
                            break;
                        case fd_spotlight:
                            add_light_source( p, 80 );
                            break;
                        case fd_dazzling:
                            add_light_source( p, 5 );
                            break;
                        default:
                            //Suppress warnings
                            break;
                        }
                    }
                }
            }
        }
    }

    for (size_t i = 0; i < g->num_zombies(); ++i) {
        auto &critter = g->zombie(i);
        if(critter.is_hallucination()) {
            continue;
        }
        const tripoint &mp = critter.pos();
        if( inbounds( mp ) ) {
            if (critter.has_effect( effect_onfire)) {
                apply_light_source( mp, 8 );
            }
            // TODO: [lightmap] Attach natural light brightness to creatures
            // TODO: [lightmap] Allow creatures to have light attacks (ie: eyebot)
            // TODO: [lightmap] Allow creatures to have facing and arc lights
            if (critter.type->luminance > 0) {
                apply_light_source( mp, critter.type->luminance );
            }
        }
    }

    // Apply any vehicle light sources
    VehicleList vehs = get_vehicles();
    for( auto &vv : vehs ) {
        vehicle *v = vv.v;
        if(v->lights_on) {
            int dir = v->face.dir();
            float veh_luminance = 0.0;
            float iteration = 1.0;
            std::vector<int> light_indices = v->all_parts_with_feature(VPFLAG_CONE_LIGHT);
            for( auto &light_indice : light_indices ) {
                veh_luminance += ( v->part_info( light_indice ).bonus / iteration );
                iteration = iteration * 1.1;
            }
            if (veh_luminance > LL_LIT) {
                for( auto &light_indice : light_indices ) {
                    tripoint pp = tripoint( vv.x, vv.y, vv.z ) +
                                  v->parts[light_indice].precalc[0];
                    if( inbounds( pp ) ) {
                        add_light_source( pp, SQRT_2 ); // Add a little surrounding light
                        apply_light_arc( pp, dir + v->parts[light_indice].direction,
                                         veh_luminance, 45 );
                    }
                }
            }
        }
        if(v->overhead_lights_on) {
            std::vector<int> light_indices = v->all_parts_with_feature(VPFLAG_CIRCLE_LIGHT);
            for( auto &light_indice : light_indices ) {
                if( ( calendar::turn % 2 &&
                      v->part_info( light_indice ).has_flag( VPFLAG_ODDTURN ) ) ||
                    ( !( calendar::turn % 2 ) &&
                      v->part_info( light_indice ).has_flag( VPFLAG_EVENTURN ) ) ||
                    ( !v->part_info( light_indice ).has_flag( VPFLAG_EVENTURN ) &&
                      !v->part_info( light_indice ).has_flag( VPFLAG_ODDTURN ) ) ) {
                    tripoint pp = tripoint( vv.x, vv.y, vv.z ) +
                                  v->parts[light_indice].precalc[0];
                    if(inbounds( pp )) {
                        add_light_source( pp, v->part_info( light_indice ).bonus );
                    }
                }
            }
        }
        // why reinvent the [lightmap] wheel
        if(v->dome_lights_on) {
            std::vector<int> light_indices = v->all_parts_with_feature(VPFLAG_DOME_LIGHT);
            for( auto &light_indice : light_indices ) {
                tripoint pp = tripoint( vv.x, vv.y, vv.z ) +
                              v->parts[light_indice].precalc[0];
                if( inbounds( pp )) {
                    add_light_source( pp, v->part_info( light_indice ).bonus );
                }
            }
        }
        if(v->aisle_lights_on) {
            std::vector<int> light_indices = v->all_parts_with_feature(VPFLAG_AISLE_LIGHT);
            for( auto &light_indice : light_indices ) {
                tripoint pp = tripoint( vv.x, vv.y, vv.z ) +
                              v->parts[light_indice].precalc[0];
                if( inbounds( pp )) {
                    add_light_source( pp, v->part_info( light_indice ).bonus );
                }
            }
        }
        if(v->has_atomic_lights) {
            // atomic light is always on
            std::vector<int> light_indices = v->all_parts_with_feature(VPFLAG_ATOMIC_LIGHT);
            for( auto &light_indice : light_indices ) {
                tripoint pp = tripoint( vv.x, vv.y, vv.z ) +
                              v->parts[light_indice].precalc[0];
                if(inbounds( pp )) {
                    add_light_source( pp, v->part_info( light_indice ).bonus );
                }
            }
        }
        for( size_t p = 0; p < v->parts.size(); ++p ) {
            tripoint pp = tripoint( vv.x, vv.y, vv.z ) +
                          v->parts[p].precalc[0];
            if( !inbounds( pp ) ) {
                continue;
            }
            if( v->part_flag( p, VPFLAG_CARGO ) && !v->part_flag( p, "COVERED" ) ) {
                add_light_from_items( pp, v->get_items(p).begin(), v->get_items(p).end() );
            }
        }
    }

    /* Now that we have position and intensity of all bulk light sources, apply_ them
      This may seem like extra work, but take a 12x12 raging inferno:
        unbuffered: (12^2)*(160*4) = apply_light_ray x 92160
        buffered:   (12*4)*(160)   = apply_light_ray x 7680
    */
    const tripoint cache_start( 0, 0, zlev );
    const tripoint cache_end( LIGHTMAP_CACHE_X, LIGHTMAP_CACHE_Y, zlev );
    for( const tripoint &p : points_in_rectangle( cache_start, cache_end ) ) {
        if( light_source_buffer[p.x][p.y] > 0.0 ) {
            apply_light_source( p, light_source_buffer[p.x][p.y] );
        }
    }


    if (g->u.has_active_bionic("bio_night") ) {
        for( const tripoint &p : points_in_rectangle( cache_start, cache_end ) ) {
            if( rl_dist( p, g->u.pos() ) < 15 ) {
                lm[p.x][p.y] = LIGHT_AMBIENT_MINIMAL;
            }
        }
    }
}
Beispiel #12
0
void light_map::generate(game* g, int x, int y, float natural_light, float luminance)
{
 build_light_cache(g, x, y);
 fill(lm, 0.0f);
 fill(sm, 0.0f);

 int dir_x[] = { 1, 0 , -1,  0 };
 int dir_y[] = { 0, 1 ,  0, -1 };
 int dir_d[] = { 180, 270, 0, 90 };

 // Daylight vision handling returned back to map due to issues it causes here
 if (natural_light > LIGHT_SOURCE_BRIGHT) {
  // Apply sunlight, first light source so just assign
  for(int sx = x - SEEX; sx <= x + SEEX; ++sx) {
   for(int sy = y - SEEY; sy <= y + SEEY; ++sy) {
    // In bright light indoor light exists to some degree
    if (!c[sx - x + LIGHTMAP_RANGE_X][sy - y + LIGHTMAP_RANGE_Y].is_outside)
     lm[sx - x + SEEX][sy - y + SEEY] = LIGHT_AMBIENT_LOW;
   }
  }
 }

 // Apply player light sources
 if (luminance > LIGHT_AMBIENT_LOW)
  apply_light_source(x, y, x, y, luminance);

 for(int sx = x - LIGHTMAP_RANGE_X; sx <= x + LIGHTMAP_RANGE_X; ++sx) {
  for(int sy = y - LIGHTMAP_RANGE_Y; sy <= y + LIGHTMAP_RANGE_Y; ++sy) {
   // When underground natural_light is 0, if this changes we need to revisit
   if (natural_light > LIGHT_AMBIENT_LOW) {
    if (!c[sx - x + LIGHTMAP_RANGE_X][sy - y + LIGHTMAP_RANGE_Y].is_outside) {
     // Apply light sources for external/internal divide
     for(int i = 0; i < 4; ++i) {
      if (INBOUNDS_LARGE(sx - x + dir_x[i], sy - y + dir_y[i]) &&
          c[sx - x + LIGHTMAP_RANGE_X + dir_x[i]][sy - y + LIGHTMAP_RANGE_Y + dir_y[i]].is_outside) {
       if (INBOUNDS(sx - x, sy - y) && c[LIGHTMAP_RANGE_X][LIGHTMAP_RANGE_Y].is_outside)
        lm[sx - x + SEEX][sy - y + SEEY] = natural_light;
       
       if (c[sx - x + LIGHTMAP_RANGE_X][sy - y + LIGHTMAP_RANGE_Y].transparency > LIGHT_TRANSPARENCY_SOLID)
       	apply_light_arc(sx, sy, dir_d[i], x, y, natural_light);
      }
	    }
    }
   }

   if (g->m.i_at(sx, sy).size() == 1 &&
       g->m.i_at(sx, sy)[0].type->id == itm_flashlight_on)
    apply_light_source(sx, sy, x, y, 20);
   
   if(g->m.ter(sx, sy) == t_lava)
    apply_light_source(sx, sy, x, y, 50);
   
   if(g->m.ter(sx, sy) == t_console)
    apply_light_source(sx, sy, x, y, 3);

   if (g->m.i_at(sx, sy).size() == 1 &&
       g->m.i_at(sx, sy)[0].type->id == itm_candle_lit)
    apply_light_source(sx, sy, x, y, 4);

   if(g->m.ter(sx, sy) == t_emergency_light)
    apply_light_source(sx, sy, x, y, 3);

   // TODO: [lightmap] Attach light brightness to fields
   switch(g->m.field_at(sx, sy).type) {
    case fd_fire:
     if (3 == g->m.field_at(sx, sy).density)
      apply_light_source(sx, sy, x, y, 160);
     else if (2 == g->m.field_at(sx, sy).density)
      apply_light_source(sx, sy, x, y, 60);
     else
      apply_light_source(sx, sy, x, y, 16);
     break;
    case fd_fire_vent:
    case fd_flame_burst:
     apply_light_source(sx, sy, x, y, 8);
     break;
    case fd_electricity:
     if (3 == g->m.field_at(sx, sy).density)
      apply_light_source(sx, sy, x, y, 8);
     else if (2 == g->m.field_at(sx, sy).density)
      apply_light_source(sx, sy, x, y, 1);
     else
      apply_light_source(sx, sy, x, y, LIGHT_SOURCE_LOCAL);  // kinda a hack as the square will still get marked
     break;
   }

   // Apply any vehicle light sources
   if (c[sx - x + LIGHTMAP_RANGE_X][sy - y + LIGHTMAP_RANGE_Y].veh &&
       c[sx - x + LIGHTMAP_RANGE_X][sy - y + LIGHTMAP_RANGE_Y].veh_light > LL_DARK) {
    if (c[sx - x + LIGHTMAP_RANGE_X][sy - y + LIGHTMAP_RANGE_Y].veh_light > LL_LIT) {
     int dir = c[sx - x + LIGHTMAP_RANGE_X][sy - y + LIGHTMAP_RANGE_Y].veh->face.dir();
     float luminance = c[sx - x + LIGHTMAP_RANGE_X][sy - y + LIGHTMAP_RANGE_Y].veh_light;
     apply_light_arc(sx, sy, dir, x, y, luminance);
    }
   }

   if (c[sx - x + LIGHTMAP_RANGE_X][sy - y + LIGHTMAP_RANGE_Y].mon >= 0) {
    if (g->z[c[sx - x + LIGHTMAP_RANGE_X][sy - y + LIGHTMAP_RANGE_Y].mon].has_effect(ME_ONFIRE))
     apply_light_source(sx, sy, x, y, 3);

    // TODO: [lightmap] Attach natural light brightness to creatures
    // TODO: [lightmap] Allow creatures to have light attacks (ie: eyebot)
    // TODO: [lightmap] Allow creatures to have facing and arc lights
    switch(g->z[c[sx - x + LIGHTMAP_RANGE_X][sy - y + LIGHTMAP_RANGE_Y].mon].type->id) {
     case mon_zombie_electric:
      apply_light_source(sx, sy, x, y, 1);
      break;
     case mon_flaming_eye:
      apply_light_source(sx, sy, x, y, LIGHT_SOURCE_BRIGHT);
      break;
     case mon_manhack:
      apply_light_source(sx, sy, x, y, LIGHT_SOURCE_LOCAL);
      break;
    }
   }
  }
 }
}
Beispiel #13
0
void light_map::generate(game* g, int x, int y, float natural_light, float luminance)
{
 build_light_cache(g, x, y);
 memset(lm, 0, sizeof(lm));
 memset(sm, 0, sizeof(sm));

 int dir_x[] = { 1, 0 , -1,  0 };
 int dir_y[] = { 0, 1 ,  0, -1 };
 int dir_d[] = { 180, 270, 0, 90 };


//g->add_msg("natural_light %f", natural_light);

//CAT-mgs: this is just for indoors to initialize it at low ambient light
 if(natural_light > LIGHT_AMBIENT_LOW) // LIGHT_SOURCE_BRIGHT
 {
	for(int sx = x - CAT_VX; sx <= x + CAT_VX; ++sx)
	{
		for(int sy = y - CAT_VY; sy <= y + CAT_VY; ++sy)
		{
			if(!is_outside(sx - x + g->u.view_offset_x, sy - y + g->u.view_offset_y))
				lm[sx - x + CAT_VX][sy - y + CAT_VY] = LIGHT_AMBIENT_LOW;	
		}
	}
 }


 if(luminance > LIGHT_AMBIENT_LOW)
  apply_light_source(g->u.posx, g->u.posy, x, y, luminance);


 for(int sx = x - LIGHTMAP_RANGE_X; sx <= x + LIGHTMAP_RANGE_X; ++sx) {
  for(int sy = y - LIGHTMAP_RANGE_Y; sy <= y + LIGHTMAP_RANGE_Y; ++sy) {
   const ter_id terrain = g->m.ter(sx, sy);
   const std::vector<item> items = g->m.i_at(sx, sy);
   const field current_field = g->m.field_at(sx, sy);

   // When underground natural_light is 0, if this changes we need to revisit
   if (natural_light > LIGHT_AMBIENT_LOW) {

    int lx= sx - x  + g->u.view_offset_x;
    int ly= sy - y + g->u.view_offset_y;

    if(!is_outside(lx, ly)) {
     // Apply light sources for external/internal divide
     for(int i = 0; i < 4; ++i) {
      if(INBOUNDS_LARGE(lx + dir_x[i], ly + dir_y[i])
			&& is_outside(lx + dir_x[i], ly + dir_y[i]))
	{

//CAT-mgs: I did that above, didn't I?
//... no, yes, what's this for anyway?
		if(INBOUNDS(sx - x, sy - y) && is_outside(0, 0))
			lm[sx - x + CAT_VX][sy - y + CAT_VY]= natural_light;

		if(c[sx - x + LIGHTMAP_RANGE_X][sy - y + LIGHTMAP_RANGE_Y].transparency > LIGHT_TRANSPARENCY_SOLID)
			apply_light_arc(sx, sy, dir_d[i], x, y, natural_light);
      }
     }
    }
   }


//CAT-g:
   if(items.size() > 0)
   {
	   if(items[0].type->id == itm_flashlight_on
			|| items[items.size()-1].type->id == itm_flashlight_on)
		apply_light_source(sx, sy, x, y, 48); 

	   if(items[0].type->id == itm_torch_lit
			|| items[items.size()-1].type->id == itm_torch_lit)
		apply_light_source(sx, sy, x, y, 20);

	   if(items[0].type->id == itm_candle_lit
			|| items[items.size()-1].type->id == itm_candle_lit)
		apply_light_source(sx, sy, x, y, 9); 
   }


   if(terrain == t_lava)
    apply_light_source(sx, sy, x, y, 48);

   if(terrain == t_console)
    apply_light_source(sx, sy, x, y, 3);

   if(terrain == t_emergency_light)
    apply_light_source(sx, sy, x, y, 3);



   // TODO: [lightmap] Attach light brightness to fields
   switch(current_field.type) {
    case fd_fire:
     if(current_field.density > 5)
      apply_light_source(sx, sy, x, y, 48);
     else if (current_field.density > 2)
      apply_light_source(sx, sy, x, y, 20);
     else
      apply_light_source(sx, sy, x, y, 9);
     break;
    case fd_fire_vent:
      apply_light_source(sx, sy, x, y, 3);
    case fd_flame_burst:
      apply_light_source(sx, sy, x, y, 8);
     break;
    case fd_electricity:
     if (3 == current_field.density)
      apply_light_source(sx, sy, x, y, 9);
     else if (2 == current_field.density)
      apply_light_source(sx, sy, x, y, 1);
     else
      apply_light_source(sx, sy, x, y, LIGHT_SOURCE_LOCAL);  // kinda a hack as the square will still get marked
     break;
   }

   // Apply any vehicle light sources
   if (c[sx - x + LIGHTMAP_RANGE_X][sy - y + LIGHTMAP_RANGE_Y].veh &&
       c[sx - x + LIGHTMAP_RANGE_X][sy - y + LIGHTMAP_RANGE_Y].veh_light > LL_DARK) {
    if (c[sx - x + LIGHTMAP_RANGE_X][sy - y + LIGHTMAP_RANGE_Y].veh_light > LL_LIT) {
     int dir = c[sx - x + LIGHTMAP_RANGE_X][sy - y + LIGHTMAP_RANGE_Y].veh->face.dir();

//CAT-g: longer range headlights
//     float luminance = c[sx - x + LIGHTMAP_RANGE_X][sy - y + LIGHTMAP_RANGE_Y].veh_light;
	 float luminance = 4000 + c[sx - x + LIGHTMAP_RANGE_X][sy - y + LIGHTMAP_RANGE_Y].veh_light;    

	apply_light_arc(sx, sy, dir, x, y, luminance);
    }
   }

   if (c[sx - x + LIGHTMAP_RANGE_X][sy - y + LIGHTMAP_RANGE_Y].mon >= 0) {
    if (g->z[c[sx - x + LIGHTMAP_RANGE_X][sy - y + LIGHTMAP_RANGE_Y].mon].has_effect(ME_ONFIRE))
     apply_light_source(sx, sy, x, y, 3);

    // TODO: [lightmap] Attach natural light brightness to creatures
    // TODO: [lightmap] Allow creatures to have light attacks (ie: eyebot)
    // TODO: [lightmap] Allow creatures to have facing and arc lights
    switch(g->z[c[sx - x + LIGHTMAP_RANGE_X][sy - y + LIGHTMAP_RANGE_Y].mon].type->id) {
     case mon_zombie_electric:
      apply_light_source(sx, sy, x, y, 1);
      break;
     case mon_turret:
      apply_light_source(sx, sy, x, y, 2);
      break;
     case mon_flaming_eye:
      apply_light_source(sx, sy, x, y, LIGHT_SOURCE_BRIGHT);
      break;
     case mon_manhack:
      apply_light_source(sx, sy, x, y, LIGHT_SOURCE_LOCAL);
      break;
    }
   }
  }
 }

}