12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268 |
- /*
- ===========================================================================
- Doom 3 GPL Source Code
- Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
- This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
- Doom 3 Source Code 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 3 of the License, or
- (at your option) any later version.
- Doom 3 Source Code 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 Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
- In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
- If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
- ===========================================================================
- */
- #include "../idlib/precompiled.h"
- #pragma hdrstop
- #include "tr_local.h"
- /*
- =================
- R_FinishDeform
- The ambientCache is on the stack, so we don't want to leave a reference
- to it that would try to be freed later. Create the ambientCache immediately.
- =================
- */
- static void R_FinishDeform( drawSurf_t *drawSurf, srfTriangles_t *newTri, idDrawVert *ac ) {
- if ( !newTri ) {
- return;
- }
- // generate current normals, tangents, and bitangents
- // We might want to support the possibility of deform functions generating
- // explicit normals, and we might also want to allow the cached deformInfo
- // optimization for these.
- // FIXME: this doesn't work, because the deformed surface is just the
- // ambient one, and there isn't an opportunity to generate light interactions
- if ( drawSurf->material->ReceivesLighting() ) {
- newTri->verts = ac;
- R_DeriveTangents( newTri, false );
- newTri->verts = NULL;
- }
- newTri->ambientCache = vertexCache.AllocFrameTemp( ac, newTri->numVerts * sizeof( idDrawVert ) );
- // if we are out of vertex cache, leave it the way it is
- if ( newTri->ambientCache ) {
- drawSurf->geo = newTri;
- }
- }
- /*
- =====================
- R_AutospriteDeform
- Assuming all the triangles for this shader are independant
- quads, rebuild them as forward facing sprites
- =====================
- */
- static void R_AutospriteDeform( drawSurf_t *surf ) {
- int i;
- const idDrawVert *v;
- idVec3 mid, delta;
- float radius;
- idVec3 left, up;
- idVec3 leftDir, upDir;
- const srfTriangles_t *tri;
- srfTriangles_t *newTri;
- tri = surf->geo;
-
- if ( tri->numVerts & 3 ) {
- common->Warning( "R_AutospriteDeform: shader had odd vertex count %f %f %f", tri->verts[0].xyz.x, tri->verts[0].xyz.y, tri->verts[0].xyz.z );
- return;
- }
- if ( tri->numIndexes != ( tri->numVerts >> 2 ) * 6 ) {
- common->Warning( "R_AutospriteDeform: autosprite had odd index count" );
- return;
- }
- R_GlobalVectorToLocal( surf->space->modelMatrix, tr.viewDef->renderView.viewaxis[1], leftDir );
- R_GlobalVectorToLocal( surf->space->modelMatrix, tr.viewDef->renderView.viewaxis[2], upDir );
- if ( tr.viewDef->isMirror ) {
- leftDir = vec3_origin - leftDir;
- }
- // this srfTriangles_t and all its indexes and caches are in frame
- // memory, and will be automatically disposed of
- newTri = (srfTriangles_t *)R_ClearedFrameAlloc( sizeof( *newTri ) );
- newTri->numVerts = tri->numVerts;
- newTri->numIndexes = tri->numIndexes;
- newTri->indexes = (glIndex_t *)R_FrameAlloc( newTri->numIndexes * sizeof( newTri->indexes[0] ) );
- idDrawVert *ac = (idDrawVert *)_alloca16( newTri->numVerts * sizeof( idDrawVert ) );
- for ( i = 0 ; i < tri->numVerts ; i+=4 ) {
- // find the midpoint
- v = &tri->verts[i];
- mid[0] = 0.25 * (v->xyz[0] + (v+1)->xyz[0] + (v+2)->xyz[0] + (v+3)->xyz[0]);
- mid[1] = 0.25 * (v->xyz[1] + (v+1)->xyz[1] + (v+2)->xyz[1] + (v+3)->xyz[1]);
- mid[2] = 0.25 * (v->xyz[2] + (v+1)->xyz[2] + (v+2)->xyz[2] + (v+3)->xyz[2]);
- delta = v->xyz - mid;
- radius = delta.Length() * 0.707; // / sqrt(2)
- left = leftDir * radius;
- up = upDir * radius;
- ac[i+0].xyz = mid + left + up;
- ac[i+0].st[0] = 0;
- ac[i+0].st[1] = 0;
- ac[i+1].xyz = mid - left + up;
- ac[i+1].st[0] = 1;
- ac[i+1].st[1] = 0;
- ac[i+2].xyz = mid - left - up;
- ac[i+2].st[0] = 1;
- ac[i+2].st[1] = 1;
- ac[i+3].xyz = mid + left - up;
- ac[i+3].st[0] = 0;
- ac[i+3].st[1] = 1;
- newTri->indexes[6*(i>>2)+0] = i;
- newTri->indexes[6*(i>>2)+1] = i+1;
- newTri->indexes[6*(i>>2)+2] = i+2;
- newTri->indexes[6*(i>>2)+3] = i;
- newTri->indexes[6*(i>>2)+4] = i+2;
- newTri->indexes[6*(i>>2)+5] = i+3;
- }
- R_FinishDeform( surf, newTri, ac );
- }
- /*
- =====================
- R_TubeDeform
- will pivot a rectangular quad along the center of its long axis
- Note that a geometric tube with even quite a few sides tube will almost certainly render much faster
- than this, so this should only be for faked volumetric tubes.
- Make sure this is used with twosided translucent shaders, because the exact side
- order may not be correct.
- =====================
- */
- static void R_TubeDeform( drawSurf_t *surf ) {
- int i, j;
- int indexes;
- const srfTriangles_t *tri;
- static int edgeVerts[6][2] = {
- { 0, 1 },
- { 1, 2 },
- { 2, 0 },
- { 3, 4 },
- { 4, 5 },
- { 5, 3 }
- };
- tri = surf->geo;
- if ( tri->numVerts & 3 ) {
- common->Error( "R_AutospriteDeform: shader had odd vertex count" );
- }
- if ( tri->numIndexes != ( tri->numVerts >> 2 ) * 6 ) {
- common->Error( "R_AutospriteDeform: autosprite had odd index count" );
- }
- // we need the view direction to project the minor axis of the tube
- // as the view changes
- idVec3 localView;
- R_GlobalPointToLocal( surf->space->modelMatrix, tr.viewDef->renderView.vieworg, localView );
- // this srfTriangles_t and all its indexes and caches are in frame
- // memory, and will be automatically disposed of
- srfTriangles_t *newTri = (srfTriangles_t *)R_ClearedFrameAlloc( sizeof( *newTri ) );
- newTri->numVerts = tri->numVerts;
- newTri->numIndexes = tri->numIndexes;
- newTri->indexes = (glIndex_t *)R_FrameAlloc( newTri->numIndexes * sizeof( newTri->indexes[0] ) );
- memcpy( newTri->indexes, tri->indexes, newTri->numIndexes * sizeof( newTri->indexes[0] ) );
- idDrawVert *ac = (idDrawVert *)_alloca16( newTri->numVerts * sizeof( idDrawVert ) );
- memset( ac, 0, sizeof( idDrawVert ) * newTri->numVerts );
- // this is a lot of work for two triangles...
- // we could precalculate a lot if it is an issue, but it would mess up
- // the shader abstraction
- for ( i = 0, indexes = 0 ; i < tri->numVerts ; i+=4, indexes+=6 ) {
- float lengths[2];
- int nums[2];
- idVec3 mid[2];
- idVec3 major, minor;
- const idDrawVert *v1, *v2;
- // identify the two shortest edges out of the six defined by the indexes
- nums[0] = nums[1] = 0;
- lengths[0] = lengths[1] = 999999;
- for ( j = 0 ; j < 6 ; j++ ) {
- float l;
- v1 = &tri->verts[tri->indexes[i+edgeVerts[j][0]]];
- v2 = &tri->verts[tri->indexes[i+edgeVerts[j][1]]];
- l = ( v1->xyz - v2->xyz ).Length();
- if ( l < lengths[0] ) {
- nums[1] = nums[0];
- lengths[1] = lengths[0];
- nums[0] = j;
- lengths[0] = l;
- } else if ( l < lengths[1] ) {
- nums[1] = j;
- lengths[1] = l;
- }
- }
- // find the midpoints of the two short edges, which
- // will give us the major axis in object coordinates
- for ( j = 0 ; j < 2 ; j++ ) {
- v1 = &tri->verts[tri->indexes[i+edgeVerts[nums[j]][0]]];
- v2 = &tri->verts[tri->indexes[i+edgeVerts[nums[j]][1]]];
- mid[j][0] = 0.5 * (v1->xyz[0] + v2->xyz[0]);
- mid[j][1] = 0.5 * (v1->xyz[1] + v2->xyz[1]);
- mid[j][2] = 0.5 * (v1->xyz[2] + v2->xyz[2]);
- }
- // find the vector of the major axis
- major = mid[1] - mid[0];
- // re-project the points
- for ( j = 0 ; j < 2 ; j++ ) {
- float l;
- int i1 = tri->indexes[i+edgeVerts[nums[j]][0]];
- int i2 = tri->indexes[i+edgeVerts[nums[j]][1]];
- idDrawVert *av1 = &ac[i1];
- idDrawVert *av2 = &ac[i2];
- *av1 = *(idDrawVert *)&tri->verts[i1];
- *av2 = *(idDrawVert *)&tri->verts[i2];
- l = 0.5 * lengths[j];
-
- // cross this with the view direction to get minor axis
- idVec3 dir = mid[j] - localView;
- minor.Cross( major, dir );
- minor.Normalize();
- if ( j ) {
- av1->xyz = mid[j] - l * minor;
- av2->xyz = mid[j] + l * minor;
- } else {
- av1->xyz = mid[j] + l * minor;
- av2->xyz = mid[j] - l * minor;
- }
- }
- }
- R_FinishDeform( surf, newTri, ac );
- }
- /*
- =====================
- R_WindingFromTriangles
- =====================
- */
- #define MAX_TRI_WINDING_INDEXES 16
- int R_WindingFromTriangles( const srfTriangles_t *tri, glIndex_t indexes[MAX_TRI_WINDING_INDEXES] ) {
- int i, j, k, l;
- indexes[0] = tri->indexes[0];
- int numIndexes = 1;
- int numTris = tri->numIndexes / 3;
- do {
- // find an edge that goes from the current index to another
- // index that isn't already used, and isn't an internal edge
- for ( i = 0 ; i < numTris ; i++ ) {
- for ( j = 0 ; j < 3 ; j++ ) {
- if ( tri->indexes[i*3+j] != indexes[numIndexes-1] ) {
- continue;
- }
- int next = tri->indexes[i*3+(j+1)%3];
- // make sure it isn't already used
- if ( numIndexes == 1 ) {
- if ( next == indexes[0] ) {
- continue;
- }
- } else {
- for ( k = 1 ; k < numIndexes ; k++ ) {
- if ( indexes[k] == next ) {
- break;
- }
- }
- if ( k != numIndexes ) {
- continue;
- }
- }
- // make sure it isn't an interior edge
- for ( k = 0 ; k < numTris ; k++ ) {
- if ( k == i ) {
- continue;
- }
- for ( l = 0 ; l < 3 ; l++ ) {
- int a, b;
- a = tri->indexes[k*3+l];
- if ( a != next ) {
- continue;
- }
- b = tri->indexes[k*3+(l+1)%3];
- if ( b != indexes[numIndexes-1] ) {
- continue;
- }
- // this is an interior edge
- break;
- }
- if ( l != 3 ) {
- break;
- }
- }
- if ( k != numTris ) {
- continue;
- }
- // add this to the list
- indexes[numIndexes] = next;
- numIndexes++;
- break;
- }
- if ( j != 3 ) {
- break;
- }
- }
- if ( numIndexes == tri->numVerts ) {
- break;
- }
- } while ( i != numTris );
- return numIndexes;
- }
- /*
- =====================
- R_FlareDeform
- =====================
- */
- /*
- static void R_FlareDeform( drawSurf_t *surf ) {
- const srfTriangles_t *tri;
- srfTriangles_t *newTri;
- idPlane plane;
- float dot;
- idVec3 localViewer;
- int j;
- tri = surf->geo;
- if ( tri->numVerts != 4 || tri->numIndexes != 6 ) {
- //FIXME: temp hack for flares on tripleted models
- common->Warning( "R_FlareDeform: not a single quad" );
- return;
- }
- // this srfTriangles_t and all its indexes and caches are in frame
- // memory, and will be automatically disposed of
- newTri = (srfTriangles_t *)R_ClearedFrameAlloc( sizeof( *newTri ) );
- newTri->numVerts = 4;
- newTri->numIndexes = 2*3;
- newTri->indexes = (glIndex_t *)R_FrameAlloc( newTri->numIndexes * sizeof( newTri->indexes[0] ) );
-
- idDrawVert *ac = (idDrawVert *)_alloca16( newTri->numVerts * sizeof( idDrawVert ) );
- // find the plane
- plane.FromPoints( tri->verts[tri->indexes[0]].xyz, tri->verts[tri->indexes[1]].xyz, tri->verts[tri->indexes[2]].xyz );
- // if viewer is behind the plane, draw nothing
- R_GlobalPointToLocal( surf->space->modelMatrix, tr.viewDef->renderView.vieworg, localViewer );
- float distFromPlane = localViewer * plane.Normal() + plane[3];
- if ( distFromPlane <= 0 ) {
- newTri->numIndexes = 0;
- surf->geo = newTri;
- return;
- }
- idVec3 center;
- center = tri->verts[0].xyz;
- for ( j = 1 ; j < tri->numVerts ; j++ ) {
- center += tri->verts[j].xyz;
- }
- center *= 1.0/tri->numVerts;
- idVec3 dir = localViewer - center;
- dir.Normalize();
- dot = dir * plane.Normal();
- // set vertex colors based on plane angle
- int color = (int)(dot * 8 * 256);
- if ( color > 255 ) {
- color = 255;
- }
- for ( j = 0 ; j < newTri->numVerts ; j++ ) {
- ac[j].color[0] =
- ac[j].color[1] =
- ac[j].color[2] = color;
- ac[j].color[3] = 255;
- }
- float spread = surf->shaderRegisters[ surf->material->GetDeformRegister(0) ] * r_flareSize.GetFloat();
- idVec3 edgeDir[4][3];
- glIndex_t indexes[MAX_TRI_WINDING_INDEXES];
- int numIndexes = R_WindingFromTriangles( tri, indexes );
- surf->material = declManager->FindMaterial( "textures/smf/anamorphicFlare" );
- // only deal with quads
- if ( numIndexes != 4 ) {
- return;
- }
- // compute centroid
- idVec3 centroid, toeye, forward, up, left;
- centroid.Set( 0, 0, 0 );
- for ( int i = 0; i < 4; i++ ) {
- centroid += tri->verts[ indexes[i] ].xyz;
- }
- centroid /= 4;
- // compute basis vectors
- up.Set( 0, 0, 1 );
- toeye = centroid - localViewer;
- toeye.Normalize();
- left = toeye.Cross( up );
- up = left.Cross( toeye );
- left = left * 40 * 6;
- up = up * 40;
- // compute flares
- struct flare_t {
- float angle;
- float length;
- };
- static flare_t flares[] = {
- { 0, 100 },
- { 90, 100 }
- };
- for ( int i = 0; i < 4; i++ ) {
- memset( ac + i, 0, sizeof( ac[i] ) );
- }
- ac[0].xyz = centroid - left;
- ac[0].st[0] = 0; ac[0].st[1] = 0;
- ac[1].xyz = centroid + up;
- ac[1].st[0] = 1; ac[1].st[1] = 0;
- ac[2].xyz = centroid + left;
- ac[2].st[0] = 1; ac[2].st[1] = 1;
- ac[3].xyz = centroid - up;
- ac[3].st[0] = 0; ac[3].st[1] = 1;
- // setup colors
- for ( j = 0 ; j < newTri->numVerts ; j++ ) {
- ac[j].color[0] =
- ac[j].color[1] =
- ac[j].color[2] = 255;
- ac[j].color[3] = 255;
- }
- // setup indexes
- static glIndex_t triIndexes[2*3] = {
- 0,1,2, 0,2,3
- };
- memcpy( newTri->indexes, triIndexes, sizeof( triIndexes ) );
- R_FinishDeform( surf, newTri, ac );
- }
- */
- static void R_FlareDeform( drawSurf_t *surf ) {
- const srfTriangles_t *tri;
- srfTriangles_t *newTri;
- idPlane plane;
- float dot;
- idVec3 localViewer;
- int j;
- tri = surf->geo;
- if ( tri->numVerts != 4 || tri->numIndexes != 6 ) {
- //FIXME: temp hack for flares on tripleted models
- common->Warning( "R_FlareDeform: not a single quad" );
- return;
- }
- // this srfTriangles_t and all its indexes and caches are in frame
- // memory, and will be automatically disposed of
- newTri = (srfTriangles_t *)R_ClearedFrameAlloc( sizeof( *newTri ) );
- newTri->numVerts = 16;
- newTri->numIndexes = 18*3;
- newTri->indexes = (glIndex_t *)R_FrameAlloc( newTri->numIndexes * sizeof( newTri->indexes[0] ) );
-
- idDrawVert *ac = (idDrawVert *)_alloca16( newTri->numVerts * sizeof( idDrawVert ) );
- // find the plane
- plane.FromPoints( tri->verts[tri->indexes[0]].xyz, tri->verts[tri->indexes[1]].xyz, tri->verts[tri->indexes[2]].xyz );
- // if viewer is behind the plane, draw nothing
- R_GlobalPointToLocal( surf->space->modelMatrix, tr.viewDef->renderView.vieworg, localViewer );
- float distFromPlane = localViewer * plane.Normal() + plane[3];
- if ( distFromPlane <= 0 ) {
- newTri->numIndexes = 0;
- surf->geo = newTri;
- return;
- }
- idVec3 center;
- center = tri->verts[0].xyz;
- for ( j = 1 ; j < tri->numVerts ; j++ ) {
- center += tri->verts[j].xyz;
- }
- center *= 1.0/tri->numVerts;
- idVec3 dir = localViewer - center;
- dir.Normalize();
- dot = dir * plane.Normal();
- // set vertex colors based on plane angle
- int color = (int)(dot * 8 * 256);
- if ( color > 255 ) {
- color = 255;
- }
- for ( j = 0 ; j < newTri->numVerts ; j++ ) {
- ac[j].color[0] =
- ac[j].color[1] =
- ac[j].color[2] = color;
- ac[j].color[3] = 255;
- }
- float spread = surf->shaderRegisters[ surf->material->GetDeformRegister(0) ] * r_flareSize.GetFloat();
- idVec3 edgeDir[4][3];
- glIndex_t indexes[MAX_TRI_WINDING_INDEXES];
- int numIndexes = R_WindingFromTriangles( tri, indexes );
- // only deal with quads
- if ( numIndexes != 4 ) {
- return;
- }
- int i;
- // calculate vector directions
- for ( i = 0 ; i < 4 ; i++ ) {
- ac[i].xyz = tri->verts[ indexes[i] ].xyz;
- ac[i].st[0] =
- ac[i].st[1] = 0.5;
- idVec3 toEye = tri->verts[ indexes[i] ].xyz - localViewer;
- toEye.Normalize();
- idVec3 d1 = tri->verts[ indexes[(i+1)%4] ].xyz - localViewer;
- d1.Normalize();
- edgeDir[i][1].Cross( toEye, d1 );
- edgeDir[i][1].Normalize();
- edgeDir[i][1] = vec3_origin - edgeDir[i][1];
- idVec3 d2 = tri->verts[ indexes[(i+3)%4] ].xyz - localViewer;
- d2.Normalize();
- edgeDir[i][0].Cross( toEye, d2 );
- edgeDir[i][0].Normalize();
- edgeDir[i][2] = edgeDir[i][0] + edgeDir[i][1];
- edgeDir[i][2].Normalize();
- }
- // build all the points
- ac[4].xyz = tri->verts[ indexes[0] ].xyz + spread * edgeDir[0][0];
- ac[4].st[0] = 0;
- ac[4].st[1] = 0.5;
- ac[5].xyz = tri->verts[ indexes[0] ].xyz + spread * edgeDir[0][2];
- ac[5].st[0] = 0;
- ac[5].st[1] = 0;
- ac[6].xyz = tri->verts[ indexes[0] ].xyz + spread * edgeDir[0][1];
- ac[6].st[0] = 0.5;
- ac[6].st[1] = 0;
- ac[7].xyz = tri->verts[ indexes[1] ].xyz + spread * edgeDir[1][0];
- ac[7].st[0] = 0.5;
- ac[7].st[1] = 0;
- ac[8].xyz = tri->verts[ indexes[1] ].xyz + spread * edgeDir[1][2];
- ac[8].st[0] = 1;
- ac[8].st[1] = 0;
- ac[9].xyz = tri->verts[ indexes[1] ].xyz + spread * edgeDir[1][1];
- ac[9].st[0] = 1;
- ac[9].st[1] = 0.5;
- ac[10].xyz = tri->verts[ indexes[2] ].xyz + spread * edgeDir[2][0];
- ac[10].st[0] = 1;
- ac[10].st[1] = 0.5;
- ac[11].xyz = tri->verts[ indexes[2] ].xyz + spread * edgeDir[2][2];
- ac[11].st[0] = 1;
- ac[11].st[1] = 1;
- ac[12].xyz = tri->verts[ indexes[2] ].xyz + spread * edgeDir[2][1];
- ac[12].st[0] = 0.5;
- ac[12].st[1] = 1;
- ac[13].xyz = tri->verts[ indexes[3] ].xyz + spread * edgeDir[3][0];
- ac[13].st[0] = 0.5;
- ac[13].st[1] = 1;
- ac[14].xyz = tri->verts[ indexes[3] ].xyz + spread * edgeDir[3][2];
- ac[14].st[0] = 0;
- ac[14].st[1] = 1;
- ac[15].xyz = tri->verts[ indexes[3] ].xyz + spread * edgeDir[3][1];
- ac[15].st[0] = 0;
- ac[15].st[1] = 0.5;
- for ( i = 4 ; i < 16 ; i++ ) {
- idVec3 dir = ac[i].xyz - localViewer;
- float len = dir.Normalize();
- float ang = dir * plane.Normal();
- // ac[i].xyz -= dir * spread * 2;
- float newLen = -( distFromPlane / ang );
- if ( newLen > 0 && newLen < len ) {
- ac[i].xyz = localViewer + dir * newLen;
- }
- ac[i].st[0] = 0;
- ac[i].st[1] = 0.5;
- }
- #if 1
- static glIndex_t triIndexes[18*3] = {
- 0,4,5, 0,5,6, 0,6,7, 0,7,1, 1,7,8, 1,8,9,
- 15,4,0, 15,0,3, 3,0,1, 3,1,2, 2,1,9, 2,9,10,
- 14,15,3, 14,3,13, 13,3,2, 13,2,12, 12,2,11, 11,2,10
- };
- #else
- newTri->numIndexes = 12;
- static glIndex_t triIndexes[4*3] = {
- 0,1,2, 0,2,3, 0,4,5,0,5,6
- };
- #endif
- memcpy( newTri->indexes, triIndexes, sizeof( triIndexes ) );
- R_FinishDeform( surf, newTri, ac );
- }
- /*
- =====================
- R_ExpandDeform
- Expands the surface along it's normals by a shader amount
- =====================
- */
- static void R_ExpandDeform( drawSurf_t *surf ) {
- int i;
- const srfTriangles_t *tri;
- srfTriangles_t *newTri;
- tri = surf->geo;
- // this srfTriangles_t and all its indexes and caches are in frame
- // memory, and will be automatically disposed of
- newTri = (srfTriangles_t *)R_ClearedFrameAlloc( sizeof( *newTri ) );
- newTri->numVerts = tri->numVerts;
- newTri->numIndexes = tri->numIndexes;
- newTri->indexes = tri->indexes;
- idDrawVert *ac = (idDrawVert *)_alloca16( newTri->numVerts * sizeof( idDrawVert ) );
- float dist = surf->shaderRegisters[ surf->material->GetDeformRegister(0) ];
- for ( i = 0 ; i < tri->numVerts ; i++ ) {
- ac[i] = *(idDrawVert *)&tri->verts[i];
- ac[i].xyz = tri->verts[i].xyz + tri->verts[i].normal * dist;
- }
- R_FinishDeform( surf, newTri, ac );
- }
- /*
- =====================
- R_MoveDeform
- Moves the surface along the X axis, mostly just for demoing the deforms
- =====================
- */
- static void R_MoveDeform( drawSurf_t *surf ) {
- int i;
- const srfTriangles_t *tri;
- srfTriangles_t *newTri;
- tri = surf->geo;
- // this srfTriangles_t and all its indexes and caches are in frame
- // memory, and will be automatically disposed of
- newTri = (srfTriangles_t *)R_ClearedFrameAlloc( sizeof( *newTri ) );
- newTri->numVerts = tri->numVerts;
- newTri->numIndexes = tri->numIndexes;
- newTri->indexes = tri->indexes;
- idDrawVert *ac = (idDrawVert *)_alloca16( newTri->numVerts * sizeof( idDrawVert ) );
- float dist = surf->shaderRegisters[ surf->material->GetDeformRegister(0) ];
- for ( i = 0 ; i < tri->numVerts ; i++ ) {
- ac[i] = *(idDrawVert *)&tri->verts[i];
- ac[i].xyz[0] += dist;
- }
- R_FinishDeform( surf, newTri, ac );
- }
- //=====================================================================================
- /*
- =====================
- R_TurbulentDeform
- Turbulently deforms the XYZ, S, and T values
- =====================
- */
- static void R_TurbulentDeform( drawSurf_t *surf ) {
- int i;
- const srfTriangles_t *tri;
- srfTriangles_t *newTri;
- tri = surf->geo;
- // this srfTriangles_t and all its indexes and caches are in frame
- // memory, and will be automatically disposed of
- newTri = (srfTriangles_t *)R_ClearedFrameAlloc( sizeof( *newTri ) );
- newTri->numVerts = tri->numVerts;
- newTri->numIndexes = tri->numIndexes;
- newTri->indexes = tri->indexes;
- idDrawVert *ac = (idDrawVert *)_alloca16( newTri->numVerts * sizeof( idDrawVert ) );
- idDeclTable *table = (idDeclTable *)surf->material->GetDeformDecl();
- float range = surf->shaderRegisters[ surf->material->GetDeformRegister(0) ];
- float timeOfs = surf->shaderRegisters[ surf->material->GetDeformRegister(1) ];
- float domain = surf->shaderRegisters[ surf->material->GetDeformRegister(2) ];
- float tOfs = 0.5;
- for ( i = 0 ; i < tri->numVerts ; i++ ) {
- float f = tri->verts[i].xyz[0] * 0.003 + tri->verts[i].xyz[1] * 0.007 + tri->verts[i].xyz[2] * 0.011;
- f = timeOfs + domain * f;
- f += timeOfs;
- ac[i] = *(idDrawVert *)&tri->verts[i];
- ac[i].st[0] += range * table->TableLookup( f );
- ac[i].st[1] += range * table->TableLookup( f + tOfs );
- }
- R_FinishDeform( surf, newTri, ac );
- }
- //=====================================================================================
- /*
- =====================
- AddTriangleToIsland_r
- =====================
- */
- #define MAX_EYEBALL_TRIS 10
- #define MAX_EYEBALL_ISLANDS 6
- typedef struct {
- int tris[MAX_EYEBALL_TRIS];
- int numTris;
- idBounds bounds;
- idVec3 mid;
- } eyeIsland_t;
- static void AddTriangleToIsland_r( const srfTriangles_t *tri, int triangleNum, bool *usedList, eyeIsland_t *island ) {
- int a, b, c;
- usedList[triangleNum] = true;
- // add to the current island
- if ( island->numTris == MAX_EYEBALL_TRIS ) {
- common->Error( "MAX_EYEBALL_TRIS" );
- }
- island->tris[island->numTris] = triangleNum;
- island->numTris++;
- // recurse into all neighbors
- a = tri->indexes[triangleNum*3];
- b = tri->indexes[triangleNum*3+1];
- c = tri->indexes[triangleNum*3+2];
- island->bounds.AddPoint( tri->verts[a].xyz );
- island->bounds.AddPoint( tri->verts[b].xyz );
- island->bounds.AddPoint( tri->verts[c].xyz );
- int numTri = tri->numIndexes / 3;
- for ( int i = 0 ; i < numTri ; i++ ) {
- if ( usedList[i] ) {
- continue;
- }
- if ( tri->indexes[i*3+0] == a
- || tri->indexes[i*3+1] == a
- || tri->indexes[i*3+2] == a
- || tri->indexes[i*3+0] == b
- || tri->indexes[i*3+1] == b
- || tri->indexes[i*3+2] == b
- || tri->indexes[i*3+0] == c
- || tri->indexes[i*3+1] == c
- || tri->indexes[i*3+2] == c ) {
- AddTriangleToIsland_r( tri, i, usedList, island );
- }
- }
- }
- /*
- =====================
- R_EyeballDeform
- Each eyeball surface should have an separate upright triangle behind it, long end
- pointing out the eye, and another single triangle in front of the eye for the focus point.
- =====================
- */
- static void R_EyeballDeform( drawSurf_t *surf ) {
- int i, j, k;
- const srfTriangles_t *tri;
- srfTriangles_t *newTri;
- eyeIsland_t islands[MAX_EYEBALL_ISLANDS];
- int numIslands;
- bool triUsed[MAX_EYEBALL_ISLANDS*MAX_EYEBALL_TRIS];
- tri = surf->geo;
- // separate all the triangles into islands
- int numTri = tri->numIndexes / 3;
- if ( numTri > MAX_EYEBALL_ISLANDS*MAX_EYEBALL_TRIS ) {
- common->Printf( "R_EyeballDeform: too many triangles in surface" );
- return;
- }
- memset( triUsed, 0, sizeof( triUsed ) );
- for ( numIslands = 0 ; numIslands < MAX_EYEBALL_ISLANDS ; numIslands++ ) {
- islands[numIslands].numTris = 0;
- islands[numIslands].bounds.Clear();
- for ( i = 0 ; i < numTri ; i++ ) {
- if ( !triUsed[i] ) {
- AddTriangleToIsland_r( tri, i, triUsed, &islands[numIslands] );
- break;
- }
- }
- if ( i == numTri ) {
- break;
- }
- }
- // assume we always have two eyes, two origins, and two targets
- if ( numIslands != 3 ) {
- common->Printf( "R_EyeballDeform: %i triangle islands\n", numIslands );
- return;
- }
- // this srfTriangles_t and all its indexes and caches are in frame
- // memory, and will be automatically disposed of
- // the surface cannot have more indexes or verts than the original
- newTri = (srfTriangles_t *)R_ClearedFrameAlloc( sizeof( *newTri ) );
- memset( newTri, 0, sizeof( *newTri ) );
- newTri->numVerts = tri->numVerts;
- newTri->numIndexes = tri->numIndexes;
- newTri->indexes = (glIndex_t *)R_FrameAlloc( tri->numIndexes * sizeof( newTri->indexes[0] ) );
- idDrawVert *ac = (idDrawVert *)_alloca16( tri->numVerts * sizeof( idDrawVert ) );
- newTri->numIndexes = 0;
- // decide which islands are the eyes and points
- for ( i = 0 ; i < numIslands ; i++ ) {
- islands[i].mid = islands[i].bounds.GetCenter();
- }
- for ( i = 0 ; i < numIslands ; i++ ) {
- eyeIsland_t *island = &islands[i];
- if ( island->numTris == 1 ) {
- continue;
- }
- // the closest single triangle point will be the eye origin
- // and the next-to-farthest will be the focal point
- idVec3 origin, focus;
- int originIsland = 0;
- float dist[MAX_EYEBALL_ISLANDS];
- int sortOrder[MAX_EYEBALL_ISLANDS];
- for ( j = 0 ; j < numIslands ; j++ ) {
- idVec3 dir = islands[j].mid - island->mid;
- dist[j] = dir.Length();
- sortOrder[j] = j;
- for ( k = j-1 ; k >= 0 ; k-- ) {
- if ( dist[k] > dist[k+1] ) {
- int temp = sortOrder[k];
- sortOrder[k] = sortOrder[k+1];
- sortOrder[k+1] = temp;
- float ftemp = dist[k];
- dist[k] = dist[k+1];
- dist[k+1] = ftemp;
- }
- }
- }
- originIsland = sortOrder[1];
- origin = islands[originIsland].mid;
- focus = islands[sortOrder[2]].mid;
- // determine the projection directions based on the origin island triangle
- idVec3 dir = focus - origin;
- dir.Normalize();
- const idVec3 &p1 = tri->verts[tri->indexes[islands[originIsland].tris[0]+0]].xyz;
- const idVec3 &p2 = tri->verts[tri->indexes[islands[originIsland].tris[0]+1]].xyz;
- const idVec3 &p3 = tri->verts[tri->indexes[islands[originIsland].tris[0]+2]].xyz;
- idVec3 v1 = p2 - p1;
- v1.Normalize();
- idVec3 v2 = p3 - p1;
- v2.Normalize();
- // texVec[0] will be the normal to the origin triangle
- idVec3 texVec[2];
- texVec[0].Cross( v1, v2 );
- texVec[1].Cross( texVec[0], dir );
- for ( j = 0 ; j < 2 ; j++ ) {
- texVec[j] -= dir * ( texVec[j] * dir );
- texVec[j].Normalize();
- }
- // emit these triangles, generating the projected texcoords
- for ( j = 0 ; j < islands[i].numTris ; j++ ) {
- for ( k = 0 ; k < 3 ; k++ ) {
- int index = islands[i].tris[j] * 3;
- index = tri->indexes[index+k];
- newTri->indexes[newTri->numIndexes++] = index;
- ac[index].xyz = tri->verts[index].xyz;
- idVec3 local = tri->verts[index].xyz - origin;
- ac[index].st[0] = 0.5 + local * texVec[0];
- ac[index].st[1] = 0.5 + local * texVec[1];
- }
- }
- }
- R_FinishDeform( surf, newTri, ac );
- }
- //==========================================================================================
- /*
- =====================
- R_ParticleDeform
- Emit particles from the surface instead of drawing it
- =====================
- */
- static void R_ParticleDeform( drawSurf_t *surf, bool useArea ) {
- const struct renderEntity_s *renderEntity = &surf->space->entityDef->parms;
- const struct viewDef_s *viewDef = tr.viewDef;
- const idDeclParticle *particleSystem = (idDeclParticle *)surf->material->GetDeformDecl();
- if ( r_skipParticles.GetBool() ) {
- return;
- }
- #if 0
- if ( renderEntity->shaderParms[SHADERPARM_PARTICLE_STOPTIME] &&
- viewDef->renderView.time*0.001 >= renderEntity->shaderParms[SHADERPARM_PARTICLE_STOPTIME] ) {
- // the entire system has faded out
- return NULL;
- }
- #endif
- //
- // calculate the area of all the triangles
- //
- int numSourceTris = surf->geo->numIndexes / 3;
- float totalArea = 0;
- float *sourceTriAreas = NULL;
- const srfTriangles_t *srcTri = surf->geo;
- if ( useArea ) {
- sourceTriAreas = (float *)_alloca( sizeof( *sourceTriAreas ) * numSourceTris );
- int triNum = 0;
- for ( int i = 0 ; i < srcTri->numIndexes ; i += 3, triNum++ ) {
- float area;
- area = idWinding::TriangleArea( srcTri->verts[srcTri->indexes[i]].xyz, srcTri->verts[srcTri->indexes[i+1]].xyz, srcTri->verts[srcTri->indexes[i+2]].xyz );
- sourceTriAreas[triNum] = totalArea;
- totalArea += area;
- }
- }
- //
- // create the particles almost exactly the way idRenderModelPrt does
- //
- particleGen_t g;
- g.renderEnt = renderEntity;
- g.renderView = &viewDef->renderView;
- g.origin.Zero();
- g.axis = mat3_identity;
- for ( int currentTri = 0; currentTri < ( ( useArea ) ? 1 : numSourceTris ); currentTri++ ) {
- for ( int stageNum = 0 ; stageNum < particleSystem->stages.Num() ; stageNum++ ) {
- idParticleStage *stage = particleSystem->stages[stageNum];
- if ( !stage->material ) {
- continue;
- }
- if ( !stage->cycleMsec ) {
- continue;
- }
- if ( stage->hidden ) { // just for gui particle editor use
- continue;
- }
- // we interpret stage->totalParticles as "particles per map square area"
- // so the systems look the same on different size surfaces
- int totalParticles = ( useArea ) ? stage->totalParticles * totalArea / 4096.0 : ( stage->totalParticles );
- int count = totalParticles * stage->NumQuadsPerParticle();
- // allocate a srfTriangles in temp memory that can hold all the particles
- srfTriangles_t *tri;
- tri = (srfTriangles_t *)R_ClearedFrameAlloc( sizeof( *tri ) );
- tri->numVerts = 4 * count;
- tri->numIndexes = 6 * count;
- tri->verts = (idDrawVert *)R_FrameAlloc( tri->numVerts * sizeof( tri->verts[0] ) );
- tri->indexes = (glIndex_t *)R_FrameAlloc( tri->numIndexes * sizeof( tri->indexes[0] ) );
- // just always draw the particles
- tri->bounds = stage->bounds;
- tri->numVerts = 0;
- idRandom steppingRandom, steppingRandom2;
- int stageAge = g.renderView->time + renderEntity->shaderParms[SHADERPARM_TIMEOFFSET] * 1000 - stage->timeOffset * 1000;
- int stageCycle = stageAge / stage->cycleMsec;
- int inCycleTime = stageAge - stageCycle * stage->cycleMsec;
- // some particles will be in this cycle, some will be in the previous cycle
- steppingRandom.SetSeed( (( stageCycle << 10 ) & idRandom::MAX_RAND) ^ (int)( renderEntity->shaderParms[SHADERPARM_DIVERSITY] * idRandom::MAX_RAND ) );
- steppingRandom2.SetSeed( (( (stageCycle-1) << 10 ) & idRandom::MAX_RAND) ^ (int)( renderEntity->shaderParms[SHADERPARM_DIVERSITY] * idRandom::MAX_RAND ) );
- for ( int index = 0 ; index < totalParticles ; index++ ) {
- g.index = index;
- // bump the random
- steppingRandom.RandomInt();
- steppingRandom2.RandomInt();
- // calculate local age for this index
- int bunchOffset = stage->particleLife * 1000 * stage->spawnBunching * index / totalParticles;
- int particleAge = stageAge - bunchOffset;
- int particleCycle = particleAge / stage->cycleMsec;
- if ( particleCycle < 0 ) {
- // before the particleSystem spawned
- continue;
- }
- if ( stage->cycles && particleCycle >= stage->cycles ) {
- // cycled systems will only run cycle times
- continue;
- }
- if ( particleCycle == stageCycle ) {
- g.random = steppingRandom;
- } else {
- g.random = steppingRandom2;
- }
- int inCycleTime = particleAge - particleCycle * stage->cycleMsec;
- if ( renderEntity->shaderParms[SHADERPARM_PARTICLE_STOPTIME] &&
- g.renderView->time - inCycleTime >= renderEntity->shaderParms[SHADERPARM_PARTICLE_STOPTIME]*1000 ) {
- // don't fire any more particles
- continue;
- }
- // supress particles before or after the age clamp
- g.frac = (float)inCycleTime / ( stage->particleLife * 1000 );
- if ( g.frac < 0 ) {
- // yet to be spawned
- continue;
- }
- if ( g.frac > 1.0 ) {
- // this particle is in the deadTime band
- continue;
- }
- //---------------
- // locate the particle origin and axis somewhere on the surface
- //---------------
- int pointTri = currentTri;
- if ( useArea ) {
- // select a triangle based on an even area distribution
- pointTri = idBinSearch_LessEqual<float>( sourceTriAreas, numSourceTris, g.random.RandomFloat() * totalArea );
- }
- // now pick a random point inside pointTri
- const idDrawVert *v1 = &srcTri->verts[ srcTri->indexes[ pointTri * 3 + 0 ] ];
- const idDrawVert *v2 = &srcTri->verts[ srcTri->indexes[ pointTri * 3 + 1 ] ];
- const idDrawVert *v3 = &srcTri->verts[ srcTri->indexes[ pointTri * 3 + 2 ] ];
- float f1 = g.random.RandomFloat();
- float f2 = g.random.RandomFloat();
- float f3 = g.random.RandomFloat();
- float ft = 1.0f / ( f1 + f2 + f3 + 0.0001f );
- f1 *= ft;
- f2 *= ft;
- f3 *= ft;
- g.origin = v1->xyz * f1 + v2->xyz * f2 + v3->xyz * f3;
- g.axis[0] = v1->tangents[0] * f1 + v2->tangents[0] * f2 + v3->tangents[0] * f3;
- g.axis[1] = v1->tangents[1] * f1 + v2->tangents[1] * f2 + v3->tangents[1] * f3;
- g.axis[2] = v1->normal * f1 + v2->normal * f2 + v3->normal * f3;
- //-----------------------
- // this is needed so aimed particles can calculate origins at different times
- g.originalRandom = g.random;
- g.age = g.frac * stage->particleLife;
- // if the particle doesn't get drawn because it is faded out or beyond a kill region,
- // don't increment the verts
- tri->numVerts += stage->CreateParticle( &g, tri->verts + tri->numVerts );
- }
-
- if ( tri->numVerts > 0 ) {
- // build the index list
- int indexes = 0;
- for ( int i = 0 ; i < tri->numVerts ; i += 4 ) {
- tri->indexes[indexes+0] = i;
- tri->indexes[indexes+1] = i+2;
- tri->indexes[indexes+2] = i+3;
- tri->indexes[indexes+3] = i;
- tri->indexes[indexes+4] = i+3;
- tri->indexes[indexes+5] = i+1;
- indexes += 6;
- }
- tri->numIndexes = indexes;
- tri->ambientCache = vertexCache.AllocFrameTemp( tri->verts, tri->numVerts * sizeof( idDrawVert ) );
- if ( tri->ambientCache ) {
- // add the drawsurf
- R_AddDrawSurf( tri, surf->space, renderEntity, stage->material, surf->scissorRect );
- }
- }
- }
- }
- }
- //========================================================================================
- /*
- =================
- R_DeformDrawSurf
- =================
- */
- void R_DeformDrawSurf( drawSurf_t *drawSurf ) {
- if ( !drawSurf->material ) {
- return;
- }
- if ( r_skipDeforms.GetBool() ) {
- return;
- }
- switch ( drawSurf->material->Deform() ) {
- case DFRM_NONE:
- return;
- case DFRM_SPRITE:
- R_AutospriteDeform( drawSurf );
- break;
- case DFRM_TUBE:
- R_TubeDeform( drawSurf );
- break;
- case DFRM_FLARE:
- R_FlareDeform( drawSurf );
- break;
- case DFRM_EXPAND:
- R_ExpandDeform( drawSurf );
- break;
- case DFRM_MOVE:
- R_MoveDeform( drawSurf );
- break;
- case DFRM_TURB:
- R_TurbulentDeform( drawSurf );
- break;
- case DFRM_EYEBALL:
- R_EyeballDeform( drawSurf );
- break;
- case DFRM_PARTICLE:
- R_ParticleDeform( drawSurf, true );
- break;
- case DFRM_PARTICLE2:
- R_ParticleDeform( drawSurf, false );
- break;
- }
- }
|