/* ============== RE_StretchPicGradient ============== */ void RE_StretchPicGradient( float x, float y, float w, float h, float s1, float t1, float s2, float t2, qhandle_t hShader, const float *gradientColor, int gradientType ) { stretchPicCommand_t *cmd; cmd = (stretchPicCommand_t*) R_GetCommandBuffer( sizeof( *cmd ) ); if ( !cmd ) { return; } cmd->commandId = RC_STRETCH_PIC_GRADIENT; cmd->shader = R_GetShaderByHandle( hShader ); cmd->x = x; cmd->y = y; cmd->w = w; cmd->h = h; cmd->s1 = s1; cmd->t1 = t1; cmd->s2 = s2; cmd->t2 = t2; if ( !gradientColor ) { static float colorWhite[ 4 ] = { 1, 1, 1, 1 }; gradientColor = colorWhite; } floatToUnorm8( gradientColor, cmd->gradientColor ); cmd->gradientType = gradientType; }
void Tess_AddTetrahedron( vec4_t tetraVerts[ 4 ], const vec4_t colorf ) { int k; u8vec4_t color; Tess_CheckOverflow( 12, 12 ); floatToUnorm8( colorf, color ); // ground triangle for ( k = 0; k < 3; k++ ) { VectorCopy( tetraVerts[ k ], tess.verts[ tess.numVertexes ].xyz ); Vector4Copy( color, tess.verts[ tess.numVertexes ].color ); tess.indexes[ tess.numIndexes++ ] = tess.numVertexes; tess.numVertexes++; } // side triangles for ( k = 0; k < 3; k++ ) { VectorCopy( tetraVerts[ 3 ], tess.verts[ tess.numVertexes ].xyz ); // offset Vector4Copy( color, tess.verts[ tess.numVertexes ].color ); tess.indexes[ tess.numIndexes++ ] = tess.numVertexes; tess.numVertexes++; VectorCopy( tetraVerts[ k ], tess.verts[ tess.numVertexes ].xyz ); Vector4Copy( color, tess.verts[ tess.numVertexes ].color ); tess.indexes[ tess.numIndexes++ ] = tess.numVertexes; tess.numVertexes++; VectorCopy( tetraVerts[( k + 1 ) % 3 ], tess.verts[ tess.numVertexes ].xyz ); Vector4Copy( color, tess.verts[ tess.numVertexes ].color ); tess.indexes[ tess.numIndexes++ ] = tess.numVertexes; tess.numVertexes++; } tess.attribsSet |= ATTR_POSITION | ATTR_COLOR; }
/* ============== Tess_AddQuadStampExt ============== */ void Tess_AddQuadStampExt( vec3_t origin, vec3_t left, vec3_t up, const vec4_t color, float s1, float t1, float s2, float t2 ) { int i; vec3_t normal; int ndx; GLimp_LogComment( "--- Tess_AddQuadStampExt ---\n" ); Tess_CheckOverflow( 4, 6 ); ndx = tess.numVertexes; // triangle indexes for a simple quad tess.indexes[ tess.numIndexes ] = ndx; tess.indexes[ tess.numIndexes + 1 ] = ndx + 1; tess.indexes[ tess.numIndexes + 2 ] = ndx + 3; tess.indexes[ tess.numIndexes + 3 ] = ndx + 3; tess.indexes[ tess.numIndexes + 4 ] = ndx + 1; tess.indexes[ tess.numIndexes + 5 ] = ndx + 2; tess.verts[ ndx ].xyz[ 0 ] = origin[ 0 ] + left[ 0 ] + up[ 0 ]; tess.verts[ ndx ].xyz[ 1 ] = origin[ 1 ] + left[ 1 ] + up[ 1 ]; tess.verts[ ndx ].xyz[ 2 ] = origin[ 2 ] + left[ 2 ] + up[ 2 ]; tess.verts[ ndx + 1 ].xyz[ 0 ] = origin[ 0 ] - left[ 0 ] + up[ 0 ]; tess.verts[ ndx + 1 ].xyz[ 1 ] = origin[ 1 ] - left[ 1 ] + up[ 1 ]; tess.verts[ ndx + 1 ].xyz[ 2 ] = origin[ 2 ] - left[ 2 ] + up[ 2 ]; tess.verts[ ndx + 2 ].xyz[ 0 ] = origin[ 0 ] - left[ 0 ] - up[ 0 ]; tess.verts[ ndx + 2 ].xyz[ 1 ] = origin[ 1 ] - left[ 1 ] - up[ 1 ]; tess.verts[ ndx + 2 ].xyz[ 2 ] = origin[ 2 ] - left[ 2 ] - up[ 2 ]; tess.verts[ ndx + 3 ].xyz[ 0 ] = origin[ 0 ] + left[ 0 ] - up[ 0 ]; tess.verts[ ndx + 3 ].xyz[ 1 ] = origin[ 1 ] + left[ 1 ] - up[ 1 ]; tess.verts[ ndx + 3 ].xyz[ 2 ] = origin[ 2 ] + left[ 2 ] - up[ 2 ]; // constant normal all the way around VectorSubtract( vec3_origin, backEnd.viewParms.orientation.axis[ 0 ], normal ); R_TBNtoQtangents( left, up, normal, tess.verts[ ndx ].qtangents ); Vector4Copy( tess.verts[ ndx ].qtangents, tess.verts[ ndx + 1 ].qtangents ); Vector4Copy( tess.verts[ ndx ].qtangents, tess.verts[ ndx + 2 ].qtangents ); Vector4Copy( tess.verts[ ndx ].qtangents, tess.verts[ ndx + 3 ].qtangents ); // standard square texture coordinates tess.verts[ ndx ].texCoords[ 0 ] = floatToHalf( s1 ); tess.verts[ ndx ].texCoords[ 1 ] = floatToHalf( t1 ); tess.verts[ ndx + 1 ].texCoords[ 0 ] = floatToHalf( s2 ); tess.verts[ ndx + 1 ].texCoords[ 1 ] = floatToHalf( t1 ); tess.verts[ ndx + 2 ].texCoords[ 0 ] = floatToHalf( s2 ); tess.verts[ ndx + 2 ].texCoords[ 1 ] = floatToHalf( t2 ); tess.verts[ ndx + 3 ].texCoords[ 0 ] = floatToHalf( s1 ); tess.verts[ ndx + 3 ].texCoords[ 1 ] = floatToHalf( t2 ); // constant color all the way around // should this be identity and let the shader specify from entity? u8vec4_t iColor; floatToUnorm8( color, iColor ); for ( i = 0; i < 4; i++ ) { Vector4Copy( iColor, tess.verts[ ndx + i ].color ); } tess.numVertexes += 4; tess.numIndexes += 6; tess.attribsSet |= ATTR_POSITION | ATTR_QTANGENT | ATTR_COLOR | ATTR_TEXCOORD; }
/* ============== Tess_AddQuadStampExt2 ============== */ void Tess_AddQuadStampExt2( vec4_t quadVerts[ 4 ], const vec4_t color, float s1, float t1, float s2, float t2 ) { int i; vec3_t normal, tangent, binormal; int ndx; GLimp_LogComment( "--- Tess_AddQuadStampExt2 ---\n" ); Tess_CheckOverflow( 4, 6 ); ndx = tess.numVertexes; // triangle indexes for a simple quad tess.indexes[ tess.numIndexes ] = ndx; tess.indexes[ tess.numIndexes + 1 ] = ndx + 1; tess.indexes[ tess.numIndexes + 2 ] = ndx + 3; tess.indexes[ tess.numIndexes + 3 ] = ndx + 3; tess.indexes[ tess.numIndexes + 4 ] = ndx + 1; tess.indexes[ tess.numIndexes + 5 ] = ndx + 2; VectorCopy( quadVerts[ 0 ], tess.verts[ ndx + 0 ].xyz ); VectorCopy( quadVerts[ 1 ], tess.verts[ ndx + 1 ].xyz ); VectorCopy( quadVerts[ 2 ], tess.verts[ ndx + 2 ].xyz ); VectorCopy( quadVerts[ 3 ], tess.verts[ ndx + 3 ].xyz ); tess.attribsSet |= ATTR_POSITION | ATTR_COLOR | ATTR_TEXCOORD | ATTR_QTANGENT; // constant normal all the way around vec2_t st[ 3 ] = { { s1, t1 }, { s2, t1 }, { s2, t2 } }; R_CalcFaceNormal( normal, quadVerts[ 0 ], quadVerts[ 1 ], quadVerts[ 2 ] ); R_CalcTangents( tangent, binormal, quadVerts[ 0 ], quadVerts[ 1 ], quadVerts[ 2 ], st[ 0 ], st[ 1 ], st[ 2 ] ); //if ( !calcNormals ) //{ // VectorNegate( backEnd.viewParms.orientation.axis[ 0 ], normal ); //} R_TBNtoQtangents( tangent, binormal, normal, tess.verts[ ndx ].qtangents ); Vector4Copy( tess.verts[ ndx ].qtangents, tess.verts[ ndx + 1 ].qtangents ); Vector4Copy( tess.verts[ ndx ].qtangents, tess.verts[ ndx + 2 ].qtangents ); Vector4Copy( tess.verts[ ndx ].qtangents, tess.verts[ ndx + 3 ].qtangents ); // standard square texture coordinates tess.verts[ ndx ].texCoords[ 0 ] = floatToHalf( s1 ); tess.verts[ ndx ].texCoords[ 1 ] = floatToHalf( t1 ); tess.verts[ ndx + 1 ].texCoords[ 0 ] = floatToHalf( s2 ); tess.verts[ ndx + 1 ].texCoords[ 1 ] = floatToHalf( t1 ); tess.verts[ ndx + 2 ].texCoords[ 0 ] = floatToHalf( s2 ); tess.verts[ ndx + 2 ].texCoords[ 1 ] = floatToHalf( t2 ); tess.verts[ ndx + 3 ].texCoords[ 0 ] = floatToHalf( s1 ); tess.verts[ ndx + 3 ].texCoords[ 1 ] = floatToHalf( t2 ); // constant color all the way around // should this be identity and let the shader specify from entity? u8vec4_t iColor; floatToUnorm8( color, iColor ); for ( i = 0; i < 4; i++ ) { Vector4Copy( iColor, tess.verts[ ndx + i ].color ); } tess.numVertexes += 4; tess.numIndexes += 6; }
bool Image::writePNG(std::ostream &os, bool strip_alpha) const { png_structp png_ptr; png_infop info_ptr; int color_type; switch (channels) { case 4: color_type = strip_alpha ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGB_ALPHA; break; case 3: color_type = PNG_COLOR_TYPE_RGB; break; case 2: color_type = PNG_COLOR_TYPE_GRAY_ALPHA; break; case 1: color_type = PNG_COLOR_TYPE_GRAY; break; default: assert(0); goto no_png; } png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) goto no_png; info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_write_struct(&png_ptr, NULL); goto no_png; } if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_write_struct(&png_ptr, &info_ptr); goto no_png; } png_set_write_fn(png_ptr, &os, pngWriteCallback, NULL); png_set_IHDR(png_ptr, info_ptr, width, height, 8, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); png_set_compression_level(png_ptr, png_compression_level); png_write_info(png_ptr, info_ptr); if (channels == 4 && strip_alpha) { png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); } switch (channelType) { case TYPE_UNORM8: for (const unsigned char *row = start(); row != end(); row += stride()) { png_write_rows(png_ptr, (png_bytepp) &row, 1); } break; case TYPE_FLOAT: png_bytep rowUnorm8 = new png_byte[width * channels]; for (const unsigned char *row = start(); row != end(); row += stride()) { const float *rowFloat = (const float *)row; for (unsigned x = 0, i = 0; x < width; ++x) { for (unsigned channel = 0; channel < channels; ++channel, ++i) { float c = rowFloat[i]; bool srgb = channels >= 3 && channel < 3; rowUnorm8[i] = srgb ? floatToSRGB(c) : floatToUnorm8(c); } } png_write_rows(png_ptr, (png_bytepp) &rowUnorm8, 1); } delete [] rowUnorm8; break; } png_write_end(png_ptr, info_ptr); png_destroy_write_struct(&png_ptr, &info_ptr); return true; no_png: return false; }