diff options
Diffstat (limited to 'src/jake2/render/jogl/Light.java')
-rw-r--r-- | src/jake2/render/jogl/Light.java | 767 |
1 files changed, 767 insertions, 0 deletions
diff --git a/src/jake2/render/jogl/Light.java b/src/jake2/render/jogl/Light.java new file mode 100644 index 0000000..fc23e4a --- /dev/null +++ b/src/jake2/render/jogl/Light.java @@ -0,0 +1,767 @@ +/* + * Light.java + * Copyright (C) 2003 + * + * $Id: Light.java,v 1.1 2004-07-07 19:59:38 hzi 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.jogl; + +import java.nio.ByteBuffer; +import java.nio.FloatBuffer; +import java.util.Arrays; + +import jake2.Defines; +import jake2.Globals; +import jake2.client.dlight_t; +import jake2.client.lightstyle_t; +import jake2.game.GameBase; +import jake2.game.cplane_t; +import jake2.qcommon.longjmpException; +import jake2.render.mnode_t; +import jake2.render.msurface_t; +import jake2.render.mtexinfo_t; +import jake2.util.Lib; +import jake2.util.Math3D; + +/** + * 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; +// vec3_t v; +// float rad; +// +// rad = light.intensity * 0.35; +// +// VectorSubtract (light.origin, r_origin, v); +// +// qglBegin (GL_TRIANGLE_FAN); +// qglColor3f (light.color[0]*0.2, light.color[1]*0.2, light.color[2]*0.2); +// for (i=0 ; i<3 ; i++) +// v[i] = light.origin[i] - vpn[i]*rad; +// qglVertex3fv (v); +// qglColor3f (0,0,0); +// for (i=16 ; i>=0 ; i--) +// { +// a = i/16.0 * M_PI*2; +// for (j=0 ; j<3 ; j++) +// v[j] = light.origin[j] + vright[j]*cos(a)*rad +// + vup[j]*sin(a)*rad; +// qglVertex3fv (v); +// } +// qglEnd (); + } + + /* + ============= + R_RenderDlights + ============= + */ + void R_RenderDlights() + { +// int i; +// dlight_t *l; +// +// if (!gl_flashblend.value) +// return; +// +// r_dlightframecount = r_framecount + 1; // because the count hasn't +// // advanced yet for this frame +// qglDepthMask (0); +// qglDisable (GL_TEXTURE_2D); +// qglShadeModel (GL_SMOOTH); +// qglEnable (GL_BLEND); +// qglBlendFunc (GL_ONE, GL_ONE); +// +// l = r_newrefdef.dlights; +// for (i=0 ; i<r_newrefdef.num_dlights ; i++, l++) +// R_RenderDlight (l); +// +// qglColor3f (1,1,1); +// qglDisable (GL_BLEND); +// qglEnable (GL_TEXTURE_2D); +// qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +// qglDepthMask (1); + } + + + /* + ============================================================================= + + DYNAMIC LIGHTS + + ============================================================================= + */ + + /* + ============= + R_MarkLights + ============= + */ + void R_MarkLights (dlight_t light, int bit, mnode_t node) + { + cplane_t splitplane; + float dist; + msurface_t surf; + int i; + + if (node.contents != -1) + return; + + splitplane = node.plane; + dist = Math3D.DotProduct (light.origin, splitplane.normal) - splitplane.dist; + + if (dist > 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<node.numsurfaces ; i++) + { + surf = r_worldmodel.surfaces[node.firstsurface + i]; + 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<r_newrefdef.num_dlights ; i++) { + l = r_newrefdef.dlights[i]; + R_MarkLights( l, 1<<i, r_worldmodel.nodes[0] ); + } + } + + + /* + ============================================================================= + + LIGHT SAMPLING + + ============================================================================= + */ + + float[] pointcolor = {0, 0, 0}; // vec3_t + cplane_t lightplane; // used as shadow plane + float[] lightspot = {0, 0, 0}; // vec3_t + + int RecursiveLightPoint (mnode_t node, float[] start, float[] end) + { + float front, back, frac; + boolean side; + int sideIndex; + cplane_t plane; + float[] mid = {0, 0, 0}; + msurface_t surf; + int s, t, ds, dt; + int i; + mtexinfo_t tex; + ByteBuffer lightmap; + int maps; + int r; + + if (node.contents != -1) + return -1; // didn't hit anything + + // calculate mid point + + // FIXME: optimize for axial + plane = node.plane; + front = Math3D.DotProduct (start, plane.normal) - plane.dist; + back = Math3D.DotProduct (end, plane.normal) - plane.dist; + side = (front < 0); + sideIndex = (side) ? 1 : 0; + + if ( (back < 0) == side) + return RecursiveLightPoint (node.children[sideIndex], start, end); + + frac = front / (front-back); + mid[0] = start[0] + (end[0] - start[0])*frac; + mid[1] = start[1] + (end[1] - start[1])*frac; + mid[2] = start[2] + (end[2] - start[2])*frac; + + // go down front side + r = RecursiveLightPoint (node.children[sideIndex], start, mid); + if (r >= 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; + for (i=0 ; i<node.numsurfaces ; i++, surfIndex++) + { + surf = r_worldmodel.surfaces[surfIndex]; + + if ((surf.flags & (Defines.SURF_DRAWTURB | Defines.SURF_DRAWSKY)) != 0) + continue; // no lightmaps + + tex = surf.texinfo; + + s = (int)(Math3D.DotProduct (mid, tex.vecs[0]) + tex.vecs[0][3]); + t = (int)(Math3D.DotProduct (mid, tex.vecs[1]) + tex.vecs[1][3]); + + if (s < surf.texturemins[0] || t < surf.texturemins[1]) + continue; + + ds = s - surf.texturemins[0]; + dt = t - surf.texturemins[1]; + + if ( ds > surf.extents[0] || dt > surf.extents[1] ) + continue; + + if (surf.samples == null) + return 0; + + ds >>= 4; + dt >>= 4; + + //surf.samples.reset(); + lightmap = surf.samples.slice(); + + int lightmapIndex = 0; + Math3D.VectorCopy (Globals.vec3_origin, pointcolor); + if (lightmap != null) + { + float[] scale = {0, 0, 0}; + +// lightmap += 3*(dt * ((surf.extents[0]>>4)+1) + ds); + lightmapIndex += 3 * (dt * ((surf.extents[0] >> 4) + 1) + ds); + + for (maps = 0 ; maps < Defines.MAXLIGHTMAPS && surf.styles[maps] != (byte)255; maps++) + { + for (i=0 ; i<3 ; i++) + scale[i] = gl_modulate.value * r_newrefdef.lightstyles[surf.styles[maps] & 0xFF].rgb[i]; + + 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); +// lightmap += 3*((surf.extents[0]>>4)+1) * +// ((surf.extents[1]>>4)+1); + 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}; + float r; + int lnum; + dlight_t dl; + float light; + float[] dist = {0, 0, 0}; + 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; + + r = RecursiveLightPoint(r_worldmodel.nodes[0], p, end); + + if (r == -1) + { + Math3D.VectorCopy (GameBase.vec3_origin, color); + } + else + { + Math3D.VectorCopy (pointcolor, color); + } + + // + // add dynamic lights + // + light = 0; + for (lnum=0 ; lnum<r_newrefdef.num_dlights ; lnum++) + { + dl = r_newrefdef.dlights[lnum]; + + Math3D.VectorSubtract (currententity.origin, dl.origin, dist); + add = dl.intensity - Math3D.VectorLength(dist); + add *= (1.0f/256); + if (add > 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 + =============== + */ + void R_AddDynamicLights(msurface_t surf) + { +// int lnum; +// int sd, td; +// float fdist, frad, fminlight; +// vec3_t impact, local; +// int s, t; +// int i; +// int smax, tmax; +// mtexinfo_t *tex; +// dlight_t *dl; +// float *pfBL; +// float fsacc, ftacc; +// +// smax = (surf.extents[0]>>4)+1; +// tmax = (surf.extents[1]>>4)+1; +// tex = surf.texinfo; +// +// for (lnum=0 ; lnum<r_newrefdef.num_dlights ; lnum++) +// { +// if ( !(surf.dlightbits & (1<<lnum) ) ) +// continue; // not lit by this light +// +// dl = &r_newrefdef.dlights[lnum]; +// frad = dl.intensity; +// fdist = DotProduct (dl.origin, surf.plane.normal) - +// surf.plane.dist; +// frad -= fabs(fdist); +// // rad is now the highest intensity on the plane +// +// fminlight = DLIGHT_CUTOFF; // FIXME: make configurable? +// if (frad < fminlight) +// continue; +// fminlight = frad - fminlight; +// +// for (i=0 ; i<3 ; i++) +// { +// impact[i] = dl.origin[i] - +// surf.plane.normal[i]*fdist; +// } +// +// local[0] = DotProduct (impact, tex.vecs[0]) + tex.vecs[0][3] - surf.texturemins[0]; +// local[1] = DotProduct (impact, tex.vecs[1]) + tex.vecs[1][3] - surf.texturemins[1]; +// +// pfBL = s_blocklights; +// for (t = 0, ftacc = 0 ; t<tmax ; t++, ftacc += 16) +// { +// td = local[1] - ftacc; +// if ( td < 0 ) +// td = -td; +// +// for ( s=0, fsacc = 0 ; s<smax ; s++, fsacc += 16, pfBL += 3) +// { +// sd = Q_ftol( local[0] - fsacc ); +// +// if ( sd < 0 ) +// sd = -sd; +// +// if (sd > td) +// fdist = sd + (td>>1); +// else +// fdist = td + (sd>>1); +// +// if ( fdist < fminlight ) +// { +// pfBL[0] += ( frad - fdist ) * dl.color[0]; +// pfBL[1] += ( frad - fdist ) * dl.color[1]; +// pfBL[2] += ( frad - fdist ) * dl.color[2]; +// } +// } +// } +// } + } + + + /* + ** R_SetCacheState + */ + void R_SetCacheState( msurface_t surf ) + { + int maps; + + for (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 + =============== + */ + void R_BuildLightMap(msurface_t surf, ByteBuffer dest, int stride) + { + int smax, tmax; + int r, g, b, a, max; + int i, j, size; + ByteBuffer lightmap; + float[] scale = {0, 0, 0, 0}; + int nummaps; + float[] bl; + lightstyle_t style; + int monolightmap; + + if ( (surf.texinfo.flags & (Defines.SURF_SKY | Defines.SURF_TRANS33 | Defines.SURF_TRANS66 | Defines.SURF_WARP)) != 0 ) + ri.Sys_Error(Defines.ERR_DROP, "R_BuildLightMap called for non-lit surface"); + + smax = (surf.extents[0] >> 4) + 1; + tmax = (surf.extents[1] >> 4) + 1; + size = smax * tmax; + if (size > ((s_blocklights.length * Defines.SIZE_OF_FLOAT) >> 4) ) + ri.Sys_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<size*3 ; i++) + s_blocklights[i] = 255; + + for (maps = 0 ; maps < Defines.MAXLIGHTMAPS && surf.styles[maps] != (byte)255; maps++) + { + style = r_newrefdef.lightstyles[surf.styles[maps] & 0xFF]; + } + // goto store; + throw new longjmpException(); + } + + // count the # of maps + for ( nummaps = 0 ; nummaps < Defines.MAXLIGHTMAPS && surf.styles[nummaps] != (byte)255 ; + nummaps++) + ; + + //surf.samples.reset(); + lightmap = surf.samples.slice(); + + // add all the lightmaps + if ( nummaps == 1 ) + { + int maps; + + for (maps = 0 ; maps < Defines.MAXLIGHTMAPS && surf.styles[maps] != (byte)255 ; + maps++) + { + bl = s_blocklights; + int blp = 0; + + for (i=0 ; i<3 ; i++) + scale[i] = gl_modulate.value * r_newrefdef.lightstyles[surf.styles[maps] & 0xFF].rgb[i]; + + if ( scale[0] == 1.0F && + scale[1] == 1.0F && + scale[2] == 1.0F ) + { + for (i=0 ; i<size ; i++) + { + bl[blp++] = lightmap.get() & 0xFF; + bl[blp++] = lightmap.get() & 0xFF; + bl[blp++] = lightmap.get() & 0xFF; + } + } + else + { + for (i=0 ; i<size ; i++) + { + bl[blp++] = (lightmap.get() & 0xFF) * scale[0]; + bl[blp++] = (lightmap.get() & 0xFF) * scale[1]; + bl[blp++] = (lightmap.get() & 0xFF) * scale[2]; + } + } + //lightmap += size*3; // skip to next lightmap + } + } + else + { + int maps; + + // memset( s_blocklights, 0, sizeof( s_blocklights[0] ) * size * 3 ); + + Arrays.fill(s_blocklights, 0, size * 3, 0.0f); + + for (maps = 0 ; maps < Defines.MAXLIGHTMAPS && surf.styles[maps] != (byte)255 ; + maps++) + { + bl = s_blocklights; + int blp = 0; + + for (i=0 ; i<3 ; i++) + scale[i] = gl_modulate.value*r_newrefdef.lightstyles[surf.styles[maps] & 0xFF].rgb[i]; + + if ( scale[0] == 1.0F && + scale[1] == 1.0F && + scale[2] == 1.0F ) + { + for (i=0 ; i<size ; i++) + { + bl[blp++] += lightmap.get() & 0xFF; + bl[blp++] += lightmap.get() & 0xFF; + bl[blp++] += lightmap.get() & 0xFF; + } + } + else + { + for (i=0 ; i<size ; i++) + { + bl[blp++] += (lightmap.get() & 0xFF) * scale[0]; + bl[blp++] += (lightmap.get() & 0xFF) * scale[1]; + bl[blp++] += (lightmap.get() & 0xFF) * scale[2]; + } + } + //lightmap += size*3; // skip to next lightmap + } + } + + // add all the dynamic lights + if (surf.dlightframe == r_framecount) + R_AddDynamicLights(surf); + + // label store: + } catch (longjmpException store) {} + + // put into texture format + stride -= (smax<<2); + bl = s_blocklights; + int blp = 0; + + monolightmap = gl_monolightmap.string.charAt(0); + + int destp = 0; + + if ( monolightmap == '0' ) + { + for (i=0 ; i<tmax ; i++, destp += stride) + { + dest.position(destp); + + for (j=0 ; j<smax ; j++) + { + + r = (int)bl[blp++]; + g = (int)bl[blp++]; + b = (int)bl[blp++]; + + // catch negative lights + if (r < 0) + r = 0; + if (g < 0) + g = 0; + if (b < 0) + b = 0; + + /* + ** determine the brightest of the three color components + */ + if (r > 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); + } + dest.put((byte)r).put((byte)g).put((byte)b).put((byte)a); + destp += 4; + } + } + } + else + { + for (i=0 ; i<tmax ; i++, destp += stride) + { + dest.position(destp); + + for (j=0 ; j<smax ; j++) + { + + r = (int) bl[blp++]; + g = (int) bl[blp++]; + b = (int) bl[blp++]; + + // catch negative lights + if (r < 0) + r = 0; + if (g < 0) + g = 0; + if (b < 0) + b = 0; + + /* + ** determine the brightest of the three color components + */ + if (r > 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; + } + + dest.put((byte)r).put((byte)g).put((byte)b).put((byte)a); + destp += 4; + } + } + } + } + +} |