wireframe

What’s the “minimum” amount of C# code you need to create a spinning wireframe quad in 3D?


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;

namespace Wireframe1
{
    public partial class Form1 : Form
    {
        List<Vertex> vertices = new List<Vertex>();

        Point prev  = new Point();
        Point curr  = new Point();
        Point first = new Point();

        float angle = 0.0f;

        public Form1()
        {
            InitializeComponent();

            vertices.Add(new Vertex(-1.0f, -1.0f, 0.0f));
            vertices.Add(new Vertex(-1.0f,  1.0f, 0.0f));
            vertices.Add(new Vertex( 1.0f,  1.0f, 0.0f));
            vertices.Add(new Vertex( 1.0f, -1.0f, 0.0f));
        }

        private void OnTick(object sender, EventArgs e)
        {
            this.Invalidate();
        }

        private void OnPaint(object sender, PaintEventArgs e)
        {
            // rotate quad a little
            int rotationTime = 8000;
            int time = System.Environment.TickCount % rotationTime;
            angle = time * (2.0f * (float)Math.PI) / rotationTime;

            for (int i = 0; i < 4; ++i)
            {
                // we don't want to alter the original vert
                Vertex v = new Vertex(vertices[i].x,
                                      vertices[i].y,
                                      vertices[i].z);

                float oldX = vertices[i].x;
                float oldY = vertices[i].y;
                float oldZ = vertices[i].z;

                // y-axis rotation
                v.x = oldX * (float) Math.Cos(angle) +
                      oldZ * (float)Math.Sin(angle);
                v.z = oldX * (float)-Math.Sin(angle) +
                      oldZ * (float)Math.Cos(angle);

                // view transform - translate inverse cam
                v.z -= -2.4f; // move camera back slightly

                // - simple perspective divide (not the best looking)
                // - note: building a perspective matrix with an
                //         arbitrary field of view is more involved
                v.x /= v.z;
                v.y /= v.z;

                // screen transform
                v.x =  v.x * 640 / 2 + 640 / 2;
                v.y = -v.y * 480 / 2 + 480 / 2;

                curr.X = (int)v.x;
                curr.Y = (int)v.y;

                if (i == 0)
                {
                    first = curr;
                    prev = curr;
                    continue;
                }

                e.Graphics.DrawLine(Pens.Black, prev, curr);
                prev = curr;

            } // end for

            e.Graphics.DrawLine(Pens.Black, curr, first);

        } // end OnPaint

    } // end Form

    public struct Vertex
    {
        public float x;
        public float y;
        public float z;

        public Vertex(float x, float y, float z)
        {
            this.x = x;
            this.y = y;
            this.z = z;
        }

    } // end Vertex

} // end namespace
 

bias

Programming is a basic skill, like reading and writing. It’s something you should possess if you’re going to successfully navigate the information age. I can’t imagine living in a world of computers and not knowing how to program – it’s absurd. Programming is sheer power and with it you can implement your ideas.

To some, programming is perceived as purely technical, there’s no art to writing a program. Of course, nothing could be further from the truth. Programmers create software by designing (and implementing) architectures of interweaving patterns of abstract concepts. However, before you get to that level of skill, you first have to master the technical. And like any other discipline, be it painter or craftsman, mastery of the technical can take years before you are able to express yourself.

signing C++/CLI assemblies

Stubbornness is a form of persistence and I’m continually amazed at my inability to give something up and move on – at least when it comes to programming. Getting a signed C++/CLI DLL to work with a C# project had me stumped for a while. Here’s the process I went through.

First, create a new solution:

Now add, a C++/CLI class library project:

I’ve called the project ClassLibrary1 and added some trivial code:


namespace ClassLibrary1
{
    public ref class Class1
    {
        public: void Foo()
        {
            Console::WriteLine("Bar");
        }
   };
}
 

The first step to making this a strong-named DLL is to generate a cryptographic key pair using sn.exe. This command line utility is located under the “Microsoft Visual Studio 8SDKv2.0Bin” directory path. To execute sn.exe you’ll need a Run prompt. To bring up the Run prompt hit the Windows+R key combo. Now type CMD and hit Enter:

You have to navigate to the Bin directory mentioned earlier. The DOS command to do this is called CD (change directory). For example:

Call sn.exe with the -k option to generate a new key pair to the specified file. In this example, a new key pair is generated and written to the file ClassLibrary1.snk:

Grab the newly generated file from the Bin folder and cut ‘n paste it into your project folder:

Inside of AssemblyInfo.cpp, add the following line of code:


[assembly:AssemblyKeyFile("ClassLibrary1.snk")];
 

Compile the project and mt.exe (manifest tool) returns the following:


general warning 810100b3: ..debugClassLibrary1.dll is a strong-name
signed assembly and embedding a manifest invalidates the signature.
You will need to re-sign this file to make it a valid assembly.
 

Okay…So let’s get rid of the embedded manifest:

A rebuild proves successful. Now add a CLR console app:

Right-click the project and select References to bring up the following dialog:

Under the Projects tab select ClassLibrary1 and click OK:

You should see the newly added ClassLibrary1 in the References section. None of the Build Properties need to be altered.

I’ve added the following code to test things out:


using namespace System;
using namespace System::Reflection;

int main(array<System::String ^>^ args)
{
    ClassLibrary1::Class1 c1;
    c1.Foo();

    for each(Assembly^ a in AppDomain::CurrentDomain->GetAssemblies())
    {
        Console::WriteLine(a->FullName);
    }

   Console::ReadLine();
   return 0;
}
 

Set ConsoleApplication1 as the startup project and test it app. Output example:

The output shows the full name of ClassLibrary1 with PublicKeyToken and hash value. Now, you may think everything is working fine but let’s see what happens when a C# project tries to use ClassLibrary1.dll. Add a new C# console project and a reference to ClassLibrary1:

As soon as you do so, the following warning pops up:

And sure enough, if you compile it, the build fails with a ResolveNativeReference task failure. So, delete the reference to ClassLibrary1. Add the reference again but this time, do so from the Browse tab:

Recompile and it builds successfully. Now, just because it compiles doesn’t mean it works, so let’s test it out.


using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            ClassLibrary1.Class1 c1 = new ClassLibrary1.Class1();
            c1.Foo();

            foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies())
            {
                Console.WriteLine(a.FullName);
            }

            Console.ReadLine();
        }
    }
}
 

Hit F5 to launch a debug session and:

The specified module could not be found. Great…but which module? After messing with this failure for a long time it turns out I should have signed the assembly in a different manner (not using the AssemblyKeyFile attribute). Have you ever signed a C# DLL? If you open the AssemblyInfo.cs file (it’s inside the Properties folder) and add the following:


[assembly: AssemblyKeyFile("SomeCSharpLibrary.snk")]
 

It returns with a warning not to use it.


Use command line option '/keyfile' or appropriate project settings instead of
'AssemblyKeyFile'
 

Visual Studio prefers you go under project properties to set the stong name.

Okay. Perhaps we can do something similar with the C++/CLI DLL? In the ClassLibrary1 project, remove the AssemblyKeyFile attribute from the AssemblyInfo.cpp file. Under the project properties, restore Embed Manifest to Yes. Now go to the Advanced section and set:

A rebuild proves successful. Run it and it works! Finally…

In the future, don’t forget to add the library via the Browse tab or you’ll get a ResolveNativeReference error.

opengl != directx

In forums you frequently see flame wars over OpenGL vs. DirectX or C++ vs. C#. The language or API in question is irrelevant. These threads are typically started by n00bs trying to decide which one to learn. Although most of these threads are quickly shutdown, it remains a legitimate question.

API consideration is important because nobody wants to make a serious investment in time and resources pursuing a language or API that is destined for obsolescence. A common occurence in ”versus threads” is a post about how it doesn’t matter which language/API you use because you can accomplish the same result with either one. It suggests they are equal and such statements are misleading. Common functionality between languages/APIs is not equivalence.

Common functionality between a language/API isn’t suprising because both are attempting solutions for the same problem domain. Yes, both APIs can render a triangle just like two audio APIs can play a sound. Even if both APIs have equivalent functionality they would still be unequal. Why? Design. Each API approaches the problem with a different solution. Both are valid solutions and both expose their solutions to the client. However, one solution is better than the other if it has better design. In other words, how complicated is it to render a triangle or play a sound? Is it client friendly? Modular? Extensible? Flexible?

So which language/API is better? It’s up to each developer to do a quantitave and qualitattive assessment. The set of tests are determined by your goals. They’re individual, customizable, and ultimately arbitrary. Once you”ve made your decision you make a vote by using a given language/API in the development of your application. Not all votes are equal. Its strength depends on the success of your application in the marketplace and/or participation in the community.

tomes

Few programming books offer substance. Most are re-hashed documentation. They are filled with tables detailing API methods, parameters, bit flags, and so forth. It’s an exercise in tedium to wade through such material. Perhaps the marketing department demands that books be of a certain size and weight. A customer is not going to spend $40 to $100 dollars on a thin book. Every fool knows a books value is proportional to its weight.

frankenstein

C++ is an object-oriented extension to the C language – two languages in one. With template metaprogramming, you can bump that number up to three. Add managed extensions into the mix and you end up with a Frankenstein monster. C++/CLI is four languages in one. And yet, just like a pug, you can’t help but find it cute.