コード例 #1
0
ファイル: lightmap.cpp プロジェクト: SweeperM/CataclysmMod
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;
    }
   }
  }
 }
}
コード例 #2
0
ファイル: lightmap.cpp プロジェクト: yowshi/Cataclysm-DDA
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 std::array<int, 4> dir_x = {{  0, -1 , 1, 0 }};   //    [0]
    constexpr std::array<int, 4> dir_y = {{ -1,  0 , 0, 1 }};   // [1][X][2]
    constexpr std::array<int, 4> 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;

        auto lights = v->lights( true );

        float veh_luminance = 0.0;
        float iteration = 1.0;

        for( const auto pt : lights ) {
            const auto &vp = pt->info();
            if( vp.has_flag( VPFLAG_CONE_LIGHT ) ) {
                veh_luminance += vp.bonus / iteration;
                iteration = iteration * 1.1;
            }
        }

        for( const auto pt : lights ) {
            const auto &vp = pt->info();
            tripoint src = v->global_part_pos3( *pt );

            if( !inbounds( src ) ) {
                continue;
            }

            if( vp.has_flag( VPFLAG_CONE_LIGHT ) ) {
                if( veh_luminance > LL_LIT ) {
                    add_light_source( src, SQRT_2 ); // Add a little surrounding light
                    apply_light_arc( src, v->face.dir() + pt->direction, veh_luminance, 45 );
                }

            } else if( vp.has_flag( VPFLAG_CIRCLE_LIGHT ) ) {
                if( (    calendar::turn % 2   && vp.has_flag( VPFLAG_ODDTURN  ) ) ||
                    ( !( calendar::turn % 2 ) && vp.has_flag( VPFLAG_EVENTURN ) ) ||
                    ( !( vp.has_flag( VPFLAG_EVENTURN ) || vp.has_flag( VPFLAG_ODDTURN ) ) ) ) {

                    add_light_source( src, vp.bonus );
                }

            } else {
                add_light_source( src, vp.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;
            }
        }
    }
}
コード例 #3
0
ファイル: lightmap.cpp プロジェクト: Justice-/MGSmod
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;
    }
   }
  }
 }

}
コード例 #4
0
ファイル: lightmap.cpp プロジェクト: yowshi/Cataclysm-DDA
void map::apply_light_ray(bool lit[LIGHTMAP_CACHE_X][LIGHTMAP_CACHE_Y],
                          const tripoint &s, const tripoint &e, float luminance)
{
    int ax = abs(e.x - s.x) * 2;
    int ay = abs(e.y - s.y) * 2;
    int dx = (s.x < e.x) ? 1 : -1;
    int dy = (s.y < e.y) ? 1 : -1;
    int x = s.x;
    int y = s.y;

    // TODO: Invert that z comparison when it's sane
    if( s.z != e.z || (s.x == e.x && s.y == e.y) ) {
        return;
    }

    auto &lm = get_cache( s.z ).lm;
    auto &transparency_cache = get_cache( s.z ).transparency_cache;

    float distance = 1.0;
    float transparency = LIGHT_TRANSPARENCY_OPEN_AIR;
    const float scaling_factor = (float)rl_dist( s, e ) /
        (float)square_dist( s, e );
    // TODO: [lightmap] Pull out the common code here rather than duplication
    if (ax > ay) {
        int t = ay - (ax / 2);
        do {
            if(t >= 0) {
                y += dy;
                t -= ax;
            }

            x += dx;
            t += ay;

            // TODO: clamp coordinates to map bounds before this method is called.
            if (INBOUNDS(x, y)) {
                if (!lit[x][y]) {
                    // Multiple rays will pass through the same squares so we need to record that
                    lit[x][y] = true;
                    lm[x][y] = std::max( lm[x][y],
                                         luminance / ((float)exp( transparency * distance ) * distance) );
                }
                float current_transparency = transparency_cache[x][y];
                if(current_transparency == LIGHT_TRANSPARENCY_SOLID) {
                    break;
                }
                // Cumulative average of the transparency values encountered.
                transparency = ((distance - 1.0) * transparency + current_transparency) / distance;
            } else {
                break;
            }

            distance += scaling_factor;
        } while(!(x == e.x && y == e.y));
    } else {
        int t = ax - (ay / 2);
        do {
            if(t >= 0) {
                x += dx;
                t -= ay;
            }

            y += dy;
            t += ax;

            if (INBOUNDS(x, y)) {
                if(!lit[x][y]) {
                    // Multiple rays will pass through the same squares so we need to record that
                    lit[x][y] = true;
                    lm[x][y] = std::max(lm[x][y],
                                        luminance / ((float)exp( transparency * distance ) * distance) );
                }
                float current_transparency = transparency_cache[x][y];
                if(current_transparency == LIGHT_TRANSPARENCY_SOLID) {
                    break;
                }
                // Cumulative average of the transparency values encountered.
                transparency = ((distance - 1.0) * transparency + current_transparency) / distance;
            } else {
                break;
            }

            distance += scaling_factor;
        } while(!(x == e.x && y == e.y));
    }
}