29 #include "../../../idlib/precompiled.h"
36 #include "../../../sys/win32/win_local.h"
39 #include "../../../renderer/tr_local.h"
61 #define DEFAULT_TRACE_FRACTION 0.05
63 #define INITIAL_TRI_TO_LINK_EXPANSION 16 // can grow as needed
64 #define HASH_AXIS_BINS 100
76 #define MAX_LINKS_PER_BLOCK 0x100000
77 #define MAX_LINK_BLOCKS 0x100
105 static float traceFraction;
106 static int rayNumber;
108 static int oldWidth, oldHeight;
115 static void SaveWindow(
void ) {
125 static void ResizeWindow(
int width,
int height ) {
127 int winWidth, winHeight;
141 winHeight = r.bottom - r.top;
142 winWidth = r.right - r.left;
145 SetWindowPos(
win32.
hWnd, HWND_TOP, 0, 0, winWidth, winHeight, SWP_SHOWWINDOW );
156 static void RestoreWindow(
void ) {
158 int winWidth, winHeight;
161 winHeight = oldHeight;
166 r.bottom = oldHeight;
172 winHeight = r.bottom - r.top;
173 winWidth = r.right - r.left;
175 SetWindowPos(
win32.
hWnd, HWND_TOP, 0, 0, winWidth, winHeight, SWP_SHOWWINDOW );
188 static void OutlineNormalMap(
byte *
data,
int width,
int height,
int emptyR,
int emptyG,
int emptyB ) {
195 memcpy( orig, data, width * height * 4 );
197 for ( i = 0 ; i <
width ; i++ ) {
198 for ( j = 0 ; j <
height ; j++ ) {
199 out = data + ( j * width +
i ) * 4;
200 if ( out[0] != emptyR || out[1] != emptyG || out[2] != emptyB ) {
205 for ( k = -1 ; k < 2 ; k++ ) {
206 for ( l = -1 ; l < 2 ; l++ ) {
209 in = orig + ( ((j+
l)&(height-1))*width + ((i+k)&(width-1)) ) * 4;
211 if ( in[0] == emptyR && in[1] == emptyG && in[2] == emptyB ) {
215 normal[0] += ( in[0] - 128 );
216 normal[1] += ( in[1] - 128 );
217 normal[2] += ( in[2] - 128 );
225 out[0] = 128 + 127 * normal[0];
226 out[1] = 128 + 127 * normal[1];
227 out[2] = 128 + 127 * normal[2];
243 static void OutlineColorMap(
byte *data,
int width,
int height,
int emptyR,
int emptyG,
int emptyB ) {
250 memcpy( orig, data, width * height * 4 );
252 for ( i = 0 ; i <
width ; i++ ) {
253 for ( j = 0 ; j <
height ; j++ ) {
254 out = data + ( j * width +
i ) * 4;
255 if ( out[0] != emptyR || out[1] != emptyG || out[2] != emptyB ) {
261 for ( k = -1 ; k < 2 ; k++ ) {
262 for ( l = -1 ; l < 2 ; l++ ) {
265 in = orig + ( ((j+
l)&(height-1))*width + ((i+k)&(width-1)) ) * 4;
267 if ( in[0] == emptyR && in[1] == emptyG && in[2] == emptyB ) {
281 normal *= (1.0 /
count );
299 static void FreeTriHash(
triHash_t *hash ) {
316 int maxLinks, numLinks;
319 memset( hash, 0,
sizeof( *hash ) );
323 for ( i = 0 ; i < highMesh->
numVerts ; i++ ) {
330 for ( i = 0 ; i < 3 ; i++ ) {
334 bounds[0][0],bounds[0][1],bounds[0][2],
335 bounds[1][0],bounds[1][1],bounds[1][2] );
349 for ( i = 0 ; i < highMesh->
numIndexes ; i+=3 ) {
352 for ( j = 0 ; j < 3 ; j++ ) {
355 for ( j = 0 ; j < 3 ; j++ ) {
356 iBounds[0][
j] = ( triBounds[0][
j] - hash->
bounds[0][
j] ) / hash->
binSize[j];
357 iBounds[0][j] -= 0.001;
358 if ( iBounds[0][j] < 0 ) {
364 iBounds[1][
j] = ( triBounds[1][
j] - hash->
bounds[0][
j] ) / hash->
binSize[j];
365 iBounds[0][j] += 0.001;
366 if ( iBounds[1][j] < 0 ) {
374 for ( j = iBounds[0][0] ; j <= iBounds[1][0] ; j++ ) {
375 for ( k = iBounds[0][1] ; k <= iBounds[1][1] ; k++ ) {
376 for ( l = iBounds[0][2] ; l <= iBounds[1][2] ; l++ ) {
377 if ( numLinks == maxLinks ) {
406 #define DIST_NO_INTERSECTION -999999999.0f
407 static float TraceToMeshFace(
const srfTriangles_t *highMesh,
int faceNum,
408 float minDist,
float maxDist,
410 byte sampledColor[4] ) {
429 d = plane->
Normal() * normal;
430 if ( d <= 0.0001
f ) {
438 testVert = point + dist * normal;
442 if ( dist > maxDist ) {
446 if ( dist < minDist ) {
453 edge = dir[0].
Cross( dir[1] );
459 edge = dir[1].
Cross( dir[2] );
464 edge = dir[2].
Cross( dir[0] );
481 if ( bary[0] + bary[1] + bary[2] > 1.1 ) {
488 for ( j = 0 ; j < 3 ; j++ ) {
493 sampledColor[0] = sampledColor[1] = sampledColor[2] = sampledColor[3] = 0;
494 for (
int i = 0 ; i < 4 ; i++ ) {
496 for ( j = 0 ; j < 3 ; j++ ) {
517 byte sampledColor[4] ) {
522 float dist, bestDist;
546 #define RAY_STEPS 100
572 for ( ; linkNum != -1 ; linkNum = link->
nextLink ) {
576 dist = TraceToMeshFace( rb->
mesh, faceNum,
577 bestDist, maxDist, point, normal, sampledNormal, sampledColor );
588 return (
bool)( bestDist > -rb->
traceDist );
598 static float TriTextureArea(
const float a[2],
const float b[2],
const float c[2] ) {
611 cross = d1.
Cross( d2 );
612 area = 0.5 * cross.
Length();
614 if ( cross[2] < 0 ) {
629 static void RasterizeTriangle(
const srfTriangles_t *lowMesh,
const idVec3 *lowMeshNormals,
int lowFaceNum,
637 byte *localDest, *globalDest, *colorDest;
640 byte sampledColor[4];
641 idVec3 point, normal, traceNormal, tangents[2];
642 float baseArea, totalArea;
658 bounds[0][0] = 99999;
659 bounds[0][1] = 99999;
660 bounds[1][0] = -99999;
661 bounds[1][1] = -99999;
662 for ( i = 0 ; i < 2 ; i++ ) {
663 for ( j = 0 ; j < 3 ; j++ ) {
664 if ( verts[j][i] < bounds[0][i] ) {
665 bounds[0][
i] = verts[
j][
i];
667 if ( verts[j][i] > bounds[1][i] ) {
668 bounds[1][
i] = verts[
j][
i];
676 const float edgeOverlap = 4.0;
678 ibounds[0][0] = floor( bounds[0][0] - edgeOverlap );
679 ibounds[1][0] = ceil( bounds[1][0] + edgeOverlap );
680 ibounds[0][1] = floor( bounds[0][1] - edgeOverlap );
681 ibounds[1][1] = ceil( bounds[1][1] + edgeOverlap );
684 for ( i = 0 ; i < 3 ; i++ ) {
690 edge[
i][0] = v2[1] - v1[1];
691 edge[
i][1] = v1[0] - v2[0];
692 float len = sqrt( edge[i][0] * edge[i][0] + edge[i][1] * edge[i][1] );
695 edge[
i][2] = -( v1[0] * edge[
i][0] + v1[1] * edge[
i][1] );
699 for ( i = ibounds[0][1] ; i < ibounds[1][1] ; i++ ) {
700 for ( j = ibounds[0][0] ; j < ibounds[1][0] ; j++ ) {
713 if ( *edgeDistance == 0 ) {
719 for ( k = 0 ; k < 3 ; k++ ) {
722 v = i * edge[k][1] + j * edge[k][0] + edge[k][2];
727 if ( ! ( ( dists[0] >= -edgeOverlap && dists[1] >= -edgeOverlap && dists[2] >= -edgeOverlap )
728 || ( dists[0] <= edgeOverlap && dists[1] <= edgeOverlap && dists[2] <= edgeOverlap ) ) ) {
734 if ( ( dists[0] >= 0 && dists[1] >= 0 && dists[2] >= 0 )
735 || ( dists[0] <= 0 && dists[1] <= 0 && dists[2] <= 0 ) ) {
741 if ( *edgeDistance == 1 ) {
751 baseArea = TriTextureArea( verts[0], verts[1], verts[2] );
752 bary[0] = TriTextureArea( testVert, verts[1], verts[2] ) / baseArea;
753 bary[1] = TriTextureArea( verts[0], testVert, verts[2] ) / baseArea;
754 bary[2] = TriTextureArea( verts[0], verts[1], testVert ) / baseArea;
756 totalArea = bary[0] + bary[1] + bary[2];
757 if ( totalArea < 0.99 || totalArea > 1.01 ) {
767 for ( k = 0 ; k < 3 ; k++ ) {
770 index = lowMesh->
indexes[lowFaceNum*3+k];
774 traceNormal += bary[k] * lowMeshNormals[
index ];
792 if ( !SampleHighMesh( rb, point, traceNormal, sampledNormal, sampledColor ) ) {
812 *edgeDistance = ( edgeTexel ? 1.0 : 0 );
815 r = 128 + 127 * sampledNormal[0];
816 g = 128 + 127 * sampledNormal[1];
817 b = 128 + 127 * sampledNormal[2];
826 mat[0] = tangents[0];
827 mat[1] = tangents[1];
830 localNormal = mat * sampledNormal;
835 r = 128 + 127 * localNormal[0];
836 g = 128 + 127 * localNormal[1];
837 b = 128 + 127 * localNormal[2];
844 colorDest[0] = sampledColor[0];
845 colorDest[1] = sampledColor[1];
846 colorDest[2] = sampledColor[2];
847 colorDest[3] = sampledColor[3];
896 indexes[numIndexes+
j] = numVerts + tri->
indexes[
j];
942 qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
956 for ( i = 0 ; i < lowMesh->
numIndexes ; i += 3, planes++ ) {
957 for ( j = 0 ; j < 3 ; j++ ) {
961 lowMeshNormals[
index] += (*planes).Normal();
965 for ( i = 0 ; i < lowMesh->
numIndexes ; i++ ) {
972 for ( j = 0 ; j < lowMesh->
numIndexes ; j+=3 ) {
976 RasterizeTriangle( lowMesh, lowMeshNormals, j/3, rb );
979 qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
998 static void WriteRenderBump(
renderBump_t *rb,
int outLinePixels ) {
1005 FreeTriHash( rb->
hash );
1013 filename.setFileExtension();
1014 filename.append(
"_nooutline.tga" );
1016 WriteTGA( filename, globalPic, width, height );
1021 for ( i = 0 ; i < outLinePixels ; i++ ) {
1022 OutlineNormalMap( rb->
localPic, width, height, 128, 128, 128 );
1023 OutlineNormalMap( rb->
globalPic, width, height, 128, 128, 128 );
1024 OutlineColorMap( rb->
colorPic, width, height, 128, 128, 128 );
1028 for ( i = 0 ; i < rb->
antiAlias ; i++ ) {
1056 filename.
Append(
"_global.tga" );
1064 filename.
Append(
"_color.tga" );
1107 rb->
hash = CreateTriHash( mesh );
1115 for ( i = 0 ; i < 3 ; i++ ) {
1118 d = rb->
traceFrac * ( bounds[1][
i] - bounds[0][
i] );
1139 for ( i = 0 ; i <
c ; i+=4 ) {
1170 const char *cmdLine;
1174 int startTime, endTime;
1180 if ( args.
Argc() != 2 ) {
1181 common->
Error(
"Usage: renderbump <lowPolyModel>" );
1189 source = args.
Argv( 1 );
1197 for ( i = 0 ; i < lowPoly->
NumSurfaces() ; i++ ) {
1201 memset( &opt, 0,
sizeof( opt ) );
1211 common->
Printf(
"surface %i, shader %s\nrenderBump = %s ", i,
1222 if ( localArgs.
Argc() < 2 ) {
1229 for ( j = 0 ; j < localArgs.
Argc() - 2; j++ ) {
1232 s = localArgs.
Argv( j );
1233 if ( s[0] ==
'-' ) {
1235 s = localArgs.
Argv( j );
1236 if ( s[0] ==
'\0' ) {
1242 if ( j + 2 >= localArgs.
Argc() ) {
1243 j = localArgs.
Argc();
1246 opt.
width = atoi( localArgs.
Argv( j + 1 ) );
1247 opt.
height = atoi( localArgs.
Argv( j + 2 ) );
1263 common->
Printf(
"WARNING: Unknown option \"%s\"\n", s );
1268 if ( j != ( localArgs.
Argc() - 2 ) ) {
1269 common->
Error(
"usage: renderBump [-size width height] [-aa <1-2>] [globalMap] [colorMap] [-trace <0.01 - 1.0>] normalMapImageFile highPolyAseFile" );
1279 for ( j = 0 ; j < numRenderBumps ; j++ ) {
1280 rb = &renderBumps[
j];
1299 if ( j == numRenderBumps ) {
1301 rb = &renderBumps[
j];
1304 InitRenderBump( rb );
1308 RenderBumpTriangles( ms->
geometry, rb );
1314 for ( i = 0 ; i < numRenderBumps ; i++ ) {
1321 common->
Printf(
"%5.2f seconds for renderBump\n", ( endTime - startTime ) / 1000.0 );
1322 common->
Printf(
"---------- RenderBump Completed ----------\n" );
1358 width = height = 256;
1362 for ( i = 1 ; i < args.
Argc() - 1; i++ ) {
1366 if ( s[0] ==
'-' ) {
1372 if ( i + 2 >= args.
Argc() ) {
1376 width = atoi( args.
Argv( i + 1 ) );
1377 height = atoi( args.
Argv( i + 2 ) );
1380 common->
Printf(
"WARNING: Unknown option \"%s\"\n", s );
1385 if ( i != ( args.
Argc() - 1 ) ) {
1386 common->
Error(
"usage: renderBumpFlat [-size width height] asefile" );
1389 common->
Printf(
"Final image size: %i, %i\n", width, height );
1393 source = args.
Argv( i );
1405 highPolyModel = CombineModelSurfaces( highPolyModel );
1417 ResizeWindow( width, height );
1437 qglOrtho( bounds[0][0], bounds[1][0], bounds[0][2],
1438 bounds[1][2], -( bounds[0][1] - 1 ), -( bounds[1][1] + 1 ) );
1448 int *sumBuffer, *colorSumBuffer;
1452 sumBuffer = (
int *)
Mem_Alloc( width * height * 4 * 4 );
1453 memset( sumBuffer, 0, width * height * 4 * 4 );
1456 colorSumBuffer = (
int *)
Mem_Alloc( width * height * 4 * 4 );
1457 memset( sumBuffer, 0, width * height * 4 * 4 );
1462 for ( sample = 0 ; sample < 16 ; sample++ ) {
1465 xOff = ( ( sample & 3 ) / 4.0 ) * ( bounds[1][0] - bounds[0][0] ) / width;
1466 yOff = ( ( sample / 4 ) / 4.0 ) * ( bounds[1][2] - bounds[0][2] ) / height;
1468 for (
int colorPass = 0 ; colorPass < 2 ; colorPass++ ) {
1470 qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
1473 for ( i = 0 ; i < highPolyModel->
NumSurfaces() ; i++ ) {
1480 for ( j = 0 ; j < mesh->
numIndexes ; j+=3 ) {
1481 for ( k = 0 ; k < 3 ; k++ ) {
1495 for ( j = 0 ; j < mesh->
numIndexes ; j+=3 ) {
1516 qglColor3f( 0.5 + 0.5*plane[0], 0.5 - 0.5*plane[2], 0.5 - 0.5*plane[1] );
1519 qglVertex3f( (*a)[0] + xOff, (*a)[2] + yOff, (*a)[1] );
1520 qglVertex3f( (*b)[0] + xOff, (*b)[2] + yOff, (*b)[1] );
1521 qglVertex3f( (*c)[0] + xOff, (*c)[2] + yOff, (*c)[1] );
1523 for ( k = 0 ; k < 3 ; k++ ) {
1537 qglColor3f( 0.5 + 0.5*n[0], 0.5 - 0.5*n[2], 0.5 - 0.5*n[1] );
1551 qglReadPixels( 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer );
1555 for ( i = 0 ; i <
c ; i++ ) {
1556 colorSumBuffer[i*4+0] += buffer[i*4+0];
1557 colorSumBuffer[i*4+1] += buffer[i*4+1];
1558 colorSumBuffer[i*4+2] += buffer[i*4+2];
1559 colorSumBuffer[i*4+3] += buffer[i*4+3];
1564 for ( i = 0 ; i <
c ; i++ ) {
1567 v[0] = ( buffer[i*4+0] - 128 ) / 127.0;
1568 v[1] = ( buffer[i*4+1] - 128 ) / 127.0;
1569 v[2] = ( buffer[i*4+2] - 128 ) / 127.0;
1573 buffer[i*4+0] = 128 + 127 * v[0];
1574 buffer[i*4+1] = 128 + 127 * v[1];
1575 buffer[i*4+2] = 128 + 127 * v[2];
1579 for ( i = 0 ; i < 8 ; i++ ) {
1580 OutlineNormalMap( buffer, width, height, 128, 128, 128 );
1584 for ( i = 0 ; i <
c ; i++ ) {
1585 sumBuffer[i*4+0] += buffer[i*4+0];
1586 sumBuffer[i*4+1] += buffer[i*4+1];
1587 sumBuffer[i*4+2] += buffer[i*4+2];
1588 sumBuffer[i*4+3] += buffer[i*4+3];
1597 for ( i = 0 ; i <
c ; i++ ) {
1598 buffer[i*4+0] = colorSumBuffer[i*4+0] / 16;
1599 buffer[i*4+1] = colorSumBuffer[i*4+1] / 16;
1600 buffer[i*4+2] = colorSumBuffer[i*4+2] / 16;
1601 buffer[i*4+3] = colorSumBuffer[i*4+3] / 16;
1605 filename.
Append(
"_color.tga" );
1607 R_WriteTGA( filename, buffer, width, height );
1612 for ( i = 0 ; i <
c ; i++ ) {
1613 buffer[i*4+0] = sumBuffer[i*4+0] / 16;
1614 buffer[i*4+1] = sumBuffer[i*4+1] / 16;
1615 buffer[i*4+2] = sumBuffer[i*4+2] / 16;
1616 buffer[i*4+3] = sumBuffer[i*4+3] / 16;
1621 filename.
Append(
"_local.tga" );
1624 R_WriteTGA( filename, buffer, width, height );
bool AddBounds(const idBounds &a)
idStr & SetFileExtension(const char *extension)
void cross(float a[], float b[], float c[])
virtual void PartialInitFromFile(const char *fileName)=0
bool FromPoints(const idVec3 &p1, const idVec3 &p2, const idVec3 &p3, bool fixDegenerate=true)
const idVec3 & Normal(void) const
#define MAX_LINKS_PER_BLOCK
const float * ToFloatPtr(void) const
#define VectorSubtract(a, b, c)
float Distance(const idVec3 &v) const
idRenderModel * highModel
int Sys_Milliseconds(void)
const idMaterial * shader
virtual void AddSurface(modelSurface_t surface)=0
byte * R_MipMap(const byte *in, int width, int height, bool preserveBorder)
const char * GetName(void) const
void RenderBump_f(const idCmdArgs &args)
srfTriangles_t * R_AllocStaticTriSurf(void)
void Sys_GenerateEvents(void)
idVec3 Cross(const idVec3 &a) const
int Icmp(const char *text) const
GLsizei GLsizei GLcharARB * source
bool AddPoint(const idVec3 &v)
GLfloat GLfloat GLfloat v2
GLuint GLuint GLsizei count
const char * GetRenderBump() const
idStr & StripFileExtension(void)
#define DIST_NO_INTERSECTION
idVec3 vec3_origin(0.0f, 0.0f, 0.0f)
char outputName[MAX_QPATH]
static float TriangleArea(const idVec3 &a, const idVec3 &b, const idVec3 &c)
void RenderBumpFlat_f(const idCmdArgs &args)
srfTriangles_t * geometry
void R_DeriveFacePlanes(srfTriangles_t *tri)
GLsizei GLsizei GLenum GLenum const GLvoid * data
virtual const modelSurface_t * Surface(int surfaceNum) const =0
virtual void virtual void FatalError(const char *fmt,...) id_attribute((format(printf
binLink_t binLinks[HASH_AXIS_BINS][HASH_AXIS_BINS][HASH_AXIS_BINS]
static void Copynz(char *dest, const char *src, int destsize)
const int GetSurfaceFlags(void) const
void R_WriteTGA(const char *filename, const byte *data, int width, int height, bool flipVertical=false)
GLubyte GLubyte GLubyte a
virtual void Printf(const char *fmt,...) id_attribute((format(printf
void R_BoundTriSurf(srfTriangles_t *tri)
virtual void FreeModel(idRenderModel *model)=0
GLenum GLsizei GLsizei height
void TokenizeString(const char *text, bool keepAsStrings)
GLfloat GLfloat GLfloat GLfloat v3
GLdouble GLdouble GLdouble r
idRenderModelManager * renderModelManager
virtual bool IsDefaultModel() const =0
void R_VerticalFlip(byte *data, int width, int height)
void Append(const char a)
void * R_StaticAlloc(int bytes)
triLink_t * linkBlocks[MAX_LINK_BLOCKS]
void * Mem_ClearedAlloc(const int size)
const char * c_str(void) const
const char * Argv(int arg) const
void R_AllocStaticTriSurfIndexes(srfTriangles_t *tri, int numIndexes)
void * Mem_Alloc(const int size)
virtual idRenderModel * CheckModel(const char *modelName)=0
virtual void SetRefreshOnPrint(bool set)=0
if(!ValidDisplayID(prefInfo.prefDisplayID)) prefInfo.prefDisplayID
void R_StaticFree(void *data)
void R_CreateSilIndexes(srfTriangles_t *tri)
virtual void Error(const char *fmt,...) id_attribute((format(printf
void R_AllocStaticTriSurfVerts(srfTriangles_t *tri, int numVerts)
void GLimp_SwapBuffers(void)
const idMaterial * defaultMaterial
virtual idRenderModel * AllocModel()=0
virtual int NumSurfaces() const =0