private static void GetSortedPoints(ref Vertex vertexA, ref Vertex vertexB, ref Vertex vertexC, ref TextureCoordinate textureA, ref TextureCoordinate textureB, ref TextureCoordinate textureC) { var point1 = vertexA; var point2 = vertexB; var point3 = vertexC; if (point2.TranslatedScreenCoordinates.Y < point1.TranslatedScreenCoordinates.Y) { var p = point1; point1 = point2; point2 = p; var t = textureA; textureA = textureB; textureB = t; } if (point3.TranslatedScreenCoordinates.Y < point2.TranslatedScreenCoordinates.Y) { var p = point2; point2 = point3; point3 = p; var t = textureB; textureB = textureC; textureC = t; } if (point2.TranslatedScreenCoordinates.Y < point1.TranslatedScreenCoordinates.Y) { var p = point1; point1 = point2; point2 = p; var t = textureA; textureA = textureB; textureB = t; } vertexA = point1; vertexB = point2; vertexC = point3; }
unsafe void InitializeFont(GDIFont font) { IntPtr hdc = myTempGraphics.GetHdc(); IntPtr hfont = font.ToHfont(); SelectObject(hdc, hfont); if (!GetCharWidth32(hdc, 0, 255, CharacterWidths)) throw new SystemException("Unable to measure character widths."); tagTEXTMETRIC metrics = new tagTEXTMETRIC(); GetTextMetrics(hdc, ref metrics); myLeadingSpace = metrics.tmInternalLeading; myTrailingSpace = metrics.tmExternalLeading; myTempGraphics.ReleaseHdc(hdc); int width = 0; for (int i = myFirstCharacterOfInterest; i <= myLastCharacterOfInterest; i++) { CharacterWidths[i] += myLeadingSpace + myTrailingSpace; width += CharacterWidths[i]; } myHeight = (int)Math.Round(myTempGraphics.MeasureString(myCharactersOfInterest, font).Height); int squareDim = (int)Math.Ceiling(Math.Sqrt(width * myHeight)); squareDim = BitmapSource.GetValidTextureDimensionFromSize(squareDim); int squareWidth = squareDim; int squareHeight = squareDim; float fSquareWidth = squareWidth; float fSquareHeight = squareHeight; Bitmap bitmap; bool fit; do { bitmap = new Bitmap(squareWidth, squareHeight, System.Drawing.Imaging.PixelFormat.Format16bppRgb565); using (Graphics g = Graphics.FromImage(bitmap)) { int x = 0; int y = 0; for (char i = myFirstCharacterOfInterest; i <= myLastCharacterOfInterest; i++) { if (x + CharacterWidths[i] >= fSquareWidth) { y += myHeight; x = 0; } CharacterLocations[i] = new Point(x, y); float uStart = x / fSquareWidth; float uEnd = (x + CharacterWidths[i]) / fSquareWidth; float vStart = y / fSquareHeight; float vEnd = (y + myHeight) / fSquareHeight; int offset = i * 4; TextureCoordinates[offset] = new TextureCoordinate(uStart, vEnd); TextureCoordinates[offset+ 1] = new TextureCoordinate(uStart, vStart); TextureCoordinates[offset + 2] = new TextureCoordinate(uEnd, vEnd); TextureCoordinates[offset + 3] = new TextureCoordinate(uEnd, vStart); g.DrawString(i.ToString(), font, myWhiteBrush, x, y); // adding a 1 pixel extra margin on the left seems to clear up some artifacting // that occurs as a result of glyphs being too close together. x += CharacterWidths[i] + 1; } fit = y + myHeight < fSquareHeight; if (!fit) { squareWidth <<= 1; fSquareWidth = squareWidth; } } } while (!fit); byte[] alphaBytes = new byte[bitmap.Width * bitmap.Height]; BitmapData data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format16bppRgb565); int pixCount = 0; for (int y = 0; y < bitmap.Height; y++) { short* yp = (short*)((int)data.Scan0 + data.Stride * y); for (int x = 0; x < bitmap.Width; x++, pixCount++) { short* p = (short*)(yp + x); short pixel = *p; byte b = (byte)((pixel & 0x1F) << 3); byte g = (byte)(((pixel >> 5) & 0x3F) << 2); byte r = (byte)(((pixel >> 11) & 0x1F) << 3); byte totalAlpha = (byte)((r + g + b) / 3); alphaBytes[pixCount] = totalAlpha; } } bitmap.UnlockBits(data); bitmap.Dispose(); uint tex = 0; gl.GenTextures(1, &tex); gl.BindTexture(gl.GL_TEXTURE_2D, tex); fixed (byte* alphaBytesPointer = alphaBytes) { gl.TexImage2D(gl.GL_TEXTURE_2D, 0, gl.GL_ALPHA, squareWidth, squareHeight, 0, gl.GL_ALPHA, gl.GL_UNSIGNED_BYTE, (IntPtr)alphaBytesPointer); } gl.TexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MIN_FILTER, gl.GL_LINEAR); gl.TexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAG_FILTER, gl.GL_LINEAR); gl.TexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_S, gl.GL_CLAMP_TO_EDGE); gl.TexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_T, gl.GL_CLAMP_TO_EDGE); mySource = new BitmapSource(); mySource.myWidth = squareWidth; mySource.myHeight = squareHeight; mySource.myName = tex; mySource.myIsTransparent = true; }
public static void Draw(IBuffers buffers, ISpanRenderer renderer, TriangleShade shade, Face face, Vertex[] vertices, TextureCoordinate[] textureCoordinates) { var vertexA = vertices[face.A]; var vertexB = vertices[face.B]; var vertexC = vertices[face.C]; var textureA = ZeroTextureCoordinate; var textureB = ZeroTextureCoordinate; var textureC = ZeroTextureCoordinate; Image image = null; ImageContext texture = null; var useTexture = false; if( null != face.Material && null != face.Material.DiffuseMap) { useTexture = true; image = face.Material.DiffuseMap; texture = face.Material.DiffuseMap.ImageContext as ImageContext; textureA = textureCoordinates[face.DiffuseA]; textureB = textureCoordinates[face.DiffuseB]; textureC = textureCoordinates[face.DiffuseC]; } /* SetSphericalEnvironmentMapTextureCoordinate(ref vertexA, ref textureA); SetSphericalEnvironmentMapTextureCoordinate(ref vertexB, ref textureB); SetSphericalEnvironmentMapTextureCoordinate(ref vertexC, ref textureC); */ GetSortedPoints(ref vertexA, ref vertexB, ref vertexC, ref textureA, ref textureB, ref textureC); var interpolator = GetInterpolatorForFace(face, shade); var secondaryStartY = (int)(vertexB.TranslatedScreenCoordinates.Y - vertexA.TranslatedScreenCoordinates.Y); var spreadCount = ((int)(vertexC.TranslatedScreenCoordinates.Y - vertexA.TranslatedScreenCoordinates.Y)) + 1; interpolator.SetPoint(0, (int)vertexA.TranslatedScreenCoordinates.X, (int)vertexC.TranslatedScreenCoordinates.X); interpolator.SetPoint(1, (int)vertexA.TranslatedScreenCoordinates.X, (int)vertexB.TranslatedScreenCoordinates.X, (int)vertexB.TranslatedScreenCoordinates.X, (int)vertexC.TranslatedScreenCoordinates.X, secondaryStartY); interpolator.SetPoint(2, vertexA.DepthBufferAdjustedZ, vertexC.DepthBufferAdjustedZ); interpolator.SetPoint(3, vertexA.DepthBufferAdjustedZ, vertexB.DepthBufferAdjustedZ, vertexB.DepthBufferAdjustedZ, vertexC.DepthBufferAdjustedZ, secondaryStartY); if (useTexture) { interpolator.SetPoint(4, textureA.U, textureC.U); interpolator.SetPoint(5, textureA.U, textureB.U, textureB.U, textureC.U, secondaryStartY); interpolator.SetPoint(6, textureA.V, textureC.V); interpolator.SetPoint(7, textureA.V, textureB.V, textureB.V, textureC.V, secondaryStartY); } var color = Color.FromArgb(0xff, 0xff, 0xff, 0xff); if (shade == TriangleShade.Gouraud && !useTexture) { var vertexAColor = vertexA.Color.ToVector(); var vertexBColor = vertexB.Color.ToVector(); var vertexCColor = vertexC.Color.ToVector(); interpolator.SetPoint(4, vertexAColor.Red, vertexCColor.Red); interpolator.SetPoint(5, vertexAColor.Red, vertexBColor.Red, vertexBColor.Red, vertexCColor.Red, secondaryStartY); interpolator.SetPoint(6, vertexAColor.Green, vertexCColor.Green); interpolator.SetPoint(7, vertexAColor.Green, vertexBColor.Green, vertexBColor.Green, vertexCColor.Green, secondaryStartY); interpolator.SetPoint(8, vertexAColor.Blue, vertexCColor.Blue); interpolator.SetPoint(9, vertexAColor.Blue, vertexBColor.Blue, vertexBColor.Blue, vertexCColor.Blue, secondaryStartY); interpolator.SetPoint(10, vertexAColor.Alpha, vertexCColor.Alpha); interpolator.SetPoint(11, vertexAColor.Alpha, vertexBColor.Alpha, vertexBColor.Alpha, vertexCColor.Alpha, secondaryStartY); } else { color = face.Color; } interpolator.Interpolate(spreadCount); var yPosition = vertexA.TranslatedScreenCoordinates.Y; var clip = false; if( null == buffers ) { return; } for (var index = 0; index < spreadCount; index++) { if( yPosition < 0 || yPosition >= buffers.Height ) { clip = true; } else { clip = false; } var span = GetSpan(index, interpolator, vertexA, useTexture); if (null != span && !clip ) { var actualSpan = (Span)span; var swapIndex = ((Span)span).Swap ? 1 : 0; actualSpan.ZStart = interpolator.Points[2 + swapIndex].InterpolatedValues[index]; actualSpan.ZEnd = interpolator.Points[3 - swapIndex].InterpolatedValues[index]; switch (shade) { case TriangleShade.Flat: { if (useTexture) { renderer.Texture(buffers, actualSpan, image, texture); } else { renderer.Flat(buffers, actualSpan, color); } } break; case TriangleShade.Gouraud: { if (useTexture) { renderer.Texture(buffers, actualSpan, image, texture); } else { actualSpan.ColorStart.Red = interpolator.Points[4 + swapIndex].InterpolatedValues[index]; actualSpan.ColorEnd.Red = interpolator.Points[5 - swapIndex].InterpolatedValues[index]; actualSpan.ColorStart.Green = interpolator.Points[6 + swapIndex].InterpolatedValues[index]; actualSpan.ColorEnd.Green = interpolator.Points[7 - swapIndex].InterpolatedValues[index]; actualSpan.ColorStart.Blue = interpolator.Points[8 + swapIndex].InterpolatedValues[index]; actualSpan.ColorEnd.Blue = interpolator.Points[9 - swapIndex].InterpolatedValues[index]; actualSpan.ColorStart.Alpha = interpolator.Points[10 + swapIndex].InterpolatedValues[index]; actualSpan.ColorEnd.Alpha = interpolator.Points[11 - swapIndex].InterpolatedValues[index]; renderer.Gouraud(buffers, actualSpan); } } break; } } yPosition++; } }
private static void SetSphericalEnvironmentMapTextureCoordinate(ref Vertex vertex, ref TextureCoordinate textureCoordinate) { var u = vertex.TransformedVectorNormalized; var n = vertex.TransformedNormal; var r = Vector.Reflect(n, u); var m = Math.Core.Sqrt((r.X * r.X) + (r.Y * r.Y) + ((r.Z + 1f) * (r.Z + 1f))); var s = (r.X / m) + 0.5f; var t = (r.Y / m) + 0.5f; textureCoordinate.U = s; textureCoordinate.V = t; }