/* * Light.java * Copyright (C) 2003 * * $Id: Light.java,v 1.2 2004-12-14 12:56:59 cawe Exp $ */ /* Copyright (C) 1997-2001 Id Software, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ package jake2.render.lwjgl; import jake2.Defines; import jake2.Globals; import jake2.client.dlight_t; import jake2.game.GameBase; import jake2.game.cplane_t; import jake2.qcommon.Com; import jake2.qcommon.longjmpException; import jake2.render.mnode_t; import jake2.render.msurface_t; import jake2.render.mtexinfo_t; import jake2.util.Math3D; import java.nio.ByteBuffer; import java.nio.IntBuffer; import java.util.Arrays; import org.lwjgl.opengl.GL11; /** * Light * * @author cwei */ public abstract class Light extends Warp { // r_light.c int r_dlightframecount; static final int DLIGHT_CUTOFF = 64; /* ============================================================================= DYNAMIC LIGHTS BLEND RENDERING ============================================================================= */ void R_RenderDlight (dlight_t light) { int i, j; float a; float[] v = {0, 0, 0}; float rad; rad = light.intensity * 0.35f; Math3D.VectorSubtract (light.origin, r_origin, v); gl.glBegin (GL11.GL_TRIANGLE_FAN); gl.glColor3f (light.color[0]*0.2f, light.color[1]*0.2f, light.color[2]*0.2f); for (i=0 ; i<3 ; i++) v[i] = light.origin[i] - vpn[i]*rad; gl.glVertex3f(v[0], v[1], v[2]); gl.glColor3f (0,0,0); for (i=16 ; i>=0 ; i--) { a = (float)(i/16.0f * Math.PI*2); for (j=0 ; j<3 ; j++) v[j] = (float)(light.origin[j] + vright[j]*Math.cos(a)*rad + vup[j]*Math.sin(a)*rad); gl.glVertex3f(v[0], v[1], v[2]); } gl.glEnd (); } /* ============= R_RenderDlights ============= */ void R_RenderDlights() { if (gl_flashblend.value == 0) return; r_dlightframecount = r_framecount + 1; // because the count hasn't // advanced yet for this frame gl.glDepthMask(false); gl.glDisable(GL11.GL_TEXTURE_2D); gl.glShadeModel (GL11.GL_SMOOTH); gl.glEnable (GL11.GL_BLEND); gl.glBlendFunc (GL11.GL_ONE, GL11.GL_ONE); for (int i=0 ; i light.intensity - DLIGHT_CUTOFF) { R_MarkLights (light, bit, node.children[0]); return; } if (dist < -light.intensity + DLIGHT_CUTOFF) { R_MarkLights (light, bit, node.children[1]); return; } // mark the polygons for (i=0 ; i= 0) ? 0 : Defines.SURF_PLANEBACK; if ( (surf.flags & Defines.SURF_PLANEBACK) != sidebit ) continue; /* * cwei * bugfix end */ if (surf.dlightframe != r_dlightframecount) { surf.dlightbits = 0; surf.dlightframe = r_dlightframecount; } surf.dlightbits |= bit; } R_MarkLights (light, bit, node.children[0]); R_MarkLights (light, bit, node.children[1]); } /* ============= R_PushDlights ============= */ void R_PushDlights() { int i; dlight_t l; if (gl_flashblend.value != 0) return; r_dlightframecount = r_framecount + 1; // because the count hasn't // advanced yet for this frame for (i=0 ; i= 0) return r; // hit something if ( (back < 0) == side ) return -1; // didn't hit anuthing // check for impact on this node Math3D.VectorCopy (mid, lightspot); lightplane = plane; int surfIndex = node.firstsurface; float[] scale = {0, 0, 0}; for (i=0 ; i surf.extents[0] || dt > surf.extents[1] ) continue; if (surf.samples == null) return 0; ds >>= 4; dt >>= 4; lightmap = surf.samples; int lightmapIndex = 0; Math3D.VectorCopy (Globals.vec3_origin, pointcolor); if (lightmap != null) { //float[] scale = {0, 0, 0}; float[] rgb; lightmapIndex += 3 * (dt * ((surf.extents[0] >> 4) + 1) + ds); for (maps = 0 ; maps < Defines.MAXLIGHTMAPS && surf.styles[maps] != (byte)255; maps++) { rgb = r_newrefdef.lightstyles[surf.styles[maps] & 0xFF].rgb; scale[0] = gl_modulate.value * rgb[0]; scale[1] = gl_modulate.value * rgb[1]; scale[2] = gl_modulate.value * rgb[2]; pointcolor[0] += (lightmap.get(lightmapIndex + 0) & 0xFF) * scale[0] * (1.0f/255); pointcolor[1] += (lightmap.get(lightmapIndex + 1) & 0xFF) * scale[1] * (1.0f/255); pointcolor[2] += (lightmap.get(lightmapIndex + 2) & 0xFF) * scale[2] * (1.0f/255); lightmapIndex += 3 * ((surf.extents[0] >> 4) + 1) * ((surf.extents[1] >> 4) + 1); } } return 1; } // go down back side return RecursiveLightPoint (node.children[1 - sideIndex], mid, end); } /* =============== R_LightPoint =============== */ void R_LightPoint (float[] p, float[] color) { assert (p.length == 3) : "vec3_t bug"; assert (color.length == 3) : "rgb bug"; float[] end = {0, 0, 0}; dlight_t dl; float add; if (r_worldmodel.lightdata == null) { color[0] = color[1] = color[2] = 1.0f; return; } end[0] = p[0]; end[1] = p[1]; end[2] = p[2] - 2048; float r = RecursiveLightPoint(r_worldmodel.nodes[0], p, end); if (r == -1) { Math3D.VectorCopy (Globals.vec3_origin, color); } else { Math3D.VectorCopy (pointcolor, color); } // // add dynamic lights // for (int lnum=0 ; lnum 0) { Math3D.VectorMA (color, add, dl.color, color); } } Math3D.VectorScale (color, gl_modulate.value, color); } // =================================================================== float[] s_blocklights = new float[34 * 34 * 3]; /* =============== R_AddDynamicLights =============== */ // TODO sync with jogl renderer. hoz void R_AddDynamicLights(msurface_t surf) { int sd, td; float fdist, frad, fminlight; float[] impact = {0, 0, 0}; float[] local = {0, 0, 0}; int s, t; dlight_t dl; float[] pfBL; float fsacc, ftacc; int smax = (surf.extents[0]>>4)+1; int tmax = (surf.extents[1]>>4)+1; mtexinfo_t tex = surf.texinfo; for (int lnum=0 ; lnum td) fdist = sd + (td>>1); else fdist = td + (sd>>1); if ( fdist < fminlight ) { pfBL[pfBLindex + 0] += ( frad - fdist ) * dl.color[0]; pfBL[pfBLindex + 1] += ( frad - fdist ) * dl.color[1]; pfBL[pfBLindex + 2] += ( frad - fdist ) * dl.color[2]; } } } } } /* ** R_SetCacheState */ void R_SetCacheState( msurface_t surf ) { for (int maps = 0 ; maps < Defines.MAXLIGHTMAPS && surf.styles[maps] != (byte)255 ; maps++) { surf.cached_light[maps] = r_newrefdef.lightstyles[surf.styles[maps] & 0xFF].white; } } /* =============== R_BuildLightMap Combine and scale multiple lightmaps into the floating format in blocklights =============== */ // TODO sync with jogl renderer. hoz void R_BuildLightMap(msurface_t surf, IntBuffer dest, int stride) { int r, g, b, a, max; int i, j; ByteBuffer lightmap; float[] scale = {0, 0, 0}; int nummaps; float[] bl; //lightstyle_t style; if ( (surf.texinfo.flags & (Defines.SURF_SKY | Defines.SURF_TRANS33 | Defines.SURF_TRANS66 | Defines.SURF_WARP)) != 0 ) Com.Error(Defines.ERR_DROP, "R_BuildLightMap called for non-lit surface"); int smax = (surf.extents[0] >> 4) + 1; int tmax = (surf.extents[1] >> 4) + 1; int size = smax * tmax; if (size > ((s_blocklights.length * Defines.SIZE_OF_FLOAT) >> 4) ) Com.Error(Defines.ERR_DROP, "Bad s_blocklights size"); try { // set to full bright if no light data if (surf.samples == null) { int maps; for (i=0 ; i g) max = r; else max = g; if (b > max) max = b; /* ** alpha is ONLY used for the mono lightmap case. For this reason ** we set it to the brightest of the color components so that ** things don't get too dim. */ a = max; /* ** rescale all the color components if the intensity of the greatest ** channel exceeds 1.0 */ if (max > 255) { float t = 255.0F / max; r = (int)(r*t); g = (int)(g*t); b = (int)(b*t); a = (int)(a*t); } //r &= 0xFF; g &= 0xFF; b &= 0xFF; a &= 0xFF; dest.put(destp++, (a << 24) | (b << 16) | (g << 8) | (r << 0)); } } } else { for (i=0 ; i g) max = r; else max = g; if (b > max) max = b; /* ** alpha is ONLY used for the mono lightmap case. For this reason ** we set it to the brightest of the color components so that ** things don't get too dim. */ a = max; /* ** rescale all the color components if the intensity of the greatest ** channel exceeds 1.0 */ if (max > 255) { float t = 255.0F / max; r = (int)(r*t); g = (int)(g*t); b = (int)(b*t); a = (int)(a*t); } /* ** So if we are doing alpha lightmaps we need to set the R, G, and B ** components to 0 and we need to set alpha to 1-alpha. */ switch ( monolightmap ) { case 'L': case 'I': r = a; g = b = 0; break; case 'C': // try faking colored lighting a = 255 - ((r+g+b)/3); r *= a/255.0f; g *= a/255.0f; b *= a/255.0f; break; case 'A': default: r = g = b = 0; a = 255 - a; break; } //r &= 0xFF; g &= 0xFF; b &= 0xFF; a &= 0xFF; dest.put(destp++, (a << 24) | (b << 16) | (g << 8) | (r << 0)); } } } } }