Dark Bit Factory & Gravity

PROGRAMMING => C / C++ /C# => Topic started by: taj on August 29, 2006

Title: 1k Trinity no ordinals
Post by: taj on August 29, 2006
Hi all,

Here is some source code.
Its 1k, devCpp, gcc compatible.
Its opengl 2.0 and ps/vs 2.0 compliant.

With no ordinal import it compresses to 1k!!!

So here is an example of how to code GLSL shaders in 1k ... in C..a first I think..
Code: [Select]
// sek the intro fairy...
// use and abuse but a credit is a wonderful thing
// t2 sek would do.

#include <process.h>
#include <windows.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glext.h>

typedef unsigned char uchar;
typedef unsigned int uint;

// the vertex shader where most of the work is done...
const GLchar *vsh="\
varying vec4 c;\
void main(){\
gl_Position=gl_Vertex+\
vec4(gl_Normal,1)*\
abs(dot(sin((gl_Vertex+ftransform())*9.9),vec4(4)));\
c=cos(gl_Position*0.04)*length(gl_Position*0.04);\
}";

// the fragment shader - do as litte as possible here...
// take c and interpolate and ssign to the ouput fragcolor...
const GLchar *fsh="\
varying vec4 c;\
void main(){\
gl_FragColor=c;\
}";

typedef void (*GenFP)(void); // any function ptr type would do
static GenFP glFP[7];

const static char* glnames[]={
             "glCreateShader", "glShaderSource", "glCompileShader",
             "glCreateProgram", "glAttachShader", "glLinkProgram", "glUseProgram"
};

static void setShaders() {
int i;

   for (i=0; i<7; i++) glFP[i] = wglGetProcAddress(glnames[i]);

GLuint v = ((PFNGLCREATESHADERPROC)(glFP[0]))(GL_VERTEX_SHADER);
GLuint f = ((PFNGLCREATESHADERPROC)(glFP[0]))(GL_FRAGMENT_SHADER);
                 GLuint p = ((PFNGLCREATEPROGRAMPROC)glFP[3])();

                ((PFNGLSHADERSOURCEPROC)glFP[1]) (v, 1, &vsh, NULL);
((PFNGLCOMPILESHADERPROC)glFP[2])(v);
((PFNGLSHADERSOURCEPROC)glFP[1]) (f, 1, &fsh, NULL);
((PFNGLCOMPILESHADERPROC)glFP[2])(f);

((PFNGLATTACHSHADERPROC)glFP[4])(p,v);
((PFNGLATTACHSHADERPROC)glFP[4])(p,f);

((PFNGLLINKPROGRAMPROC)glFP[5])(p);
((PFNGLUSEPROGRAMPROC) glFP[6])(p);


}


static PIXELFORMATDESCRIPTOR pfd;

void WINAPI WinMainCRTStartup()
{
      // minimal windows setup code for opengl 
      pfd.cColorBits = pfd.cDepthBits = 32;
      pfd.dwFlags    = PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
   
      PVOID hDC= GetDC ( CreateWindow("edit", 0,
                    WS_POPUP|WS_VISIBLE|WS_CLIPSIBLINGS|WS_CLIPCHILDREN|WS_MAXIMIZE,
                    0, 0, 0,0, 0, 0, 0, 0) ); 
      SetPixelFormat ( hDC, ChoosePixelFormat ( hDC, &pfd) , &pfd );
      wglMakeCurrent ( hDC, wglCreateContext(hDC) );

      setShaders();
      ShowCursor(FALSE);

//**********************
// NOW THE MAIN LOOP...
//**********************

    // there is no depth test or clear screen...as we draw in order and cover
    // the whole area of the screen.
    do {
         // we draw 3 spheres using the same shader which is *very* senesitive to radius
         // so we see a 3 fold effect ... a trinity
         glRotatef(3,3,3,3);
         gluSphere(gluNewQuadric(),1.6,200,200);
         gluSphere(gluNewQuadric(),1.04,200,200);
         gluSphere(gluNewQuadric(),0.4,200,200);
         SwapBuffers(hDC);
    } while ( !GetAsyncKeyState(VK_ESCAPE) );   
}

It draws 3 spheres and rotates them.
In order to apply different shaders simply substitute different strings for vsh and fsh.


TheFairy
Title: Re: 1k Trinity no ordinals
Post by: taj on August 30, 2006
Here is the executable.
Once again: No ordinals, so can run on any machine that has shader model 2.0+.
Title: Re: 1k Trinity no ordinals
Post by: Shockwave on August 30, 2006
Props for posting the source :) It's cool.
Title: Re: 1k Trinity no ordinals
Post by: Rbz on August 30, 2006
Nice one, and reminds me to start learning how to code those pixel/vertex shaders  8)
Title: Re: 1k Trinity no ordinals
Post by: taj on August 31, 2006
Rbraz, if you need help just ask me, and Ill happily swap ideas for some help with my assembler  ;)
Title: Re: 1k Trinity no ordinals
Post by: benny! on April 19, 2007
Hi.

while waiting for taj sources ( hi Chris, just kidding - take your time ;) ). I had a
look on this code. I converted the project work with Visual Studio C++ 2oo5. It
just needed some minor modifications ( see attached code ).

Code: [Select]
// sek the intro fairy...
// use and abuse but a credit is a wonderful thing
// t2 sek would do.

// VS2005 modifications by benny!weltenkonstrukteur.de

#include <process.h>
#include <windows.h>
#include <GL/gl.h>
#include <GL/glu.h>
//#include <GL/glext.h>
#include "glext.h"

typedef unsigned char uchar;
typedef unsigned int uint;

// the vertex shader where most of the work is done...
const GLchar *vsh="\
varying vec4 c;\
void main(){\
gl_Position=gl_Vertex+\
vec4(gl_Normal,1)*\
abs(dot(sin((gl_Vertex+ftransform())*9.9),vec4(4)));\
c=cos(gl_Position*0.04)*length(gl_Position*0.04);\
}";

// the fragment shader - do as litte as possible here...
// take c and interpolate and ssign to the ouput fragcolor...
const GLchar *fsh="\
varying vec4 c;\
void main(){\
gl_FragColor=c;\
}";

typedef void (*GenFP)(void); // any function ptr type would do
static GenFP glFP[7];

const static char* glnames[]={
             "glCreateShader", "glShaderSource", "glCompileShader",
             "glCreateProgram", "glAttachShader", "glLinkProgram", "glUseProgram"
};

static void setShaders() {
int i;
   // 19. April 2007: "(GenFP) cast" added by benny!weltenkonstrukteur.de
   for (i=0; i<7; i++) glFP[i] = (GenFP)wglGetProcAddress(glnames[i]);

GLuint v = ((PFNGLCREATESHADERPROC)(glFP[0]))(GL_VERTEX_SHADER);
GLuint f = ((PFNGLCREATESHADERPROC)(glFP[0]))(GL_FRAGMENT_SHADER);
                 GLuint p = ((PFNGLCREATEPROGRAMPROC)glFP[3])();

                ((PFNGLSHADERSOURCEPROC)glFP[1]) (v, 1, &vsh, NULL);
((PFNGLCOMPILESHADERPROC)glFP[2])(v);
((PFNGLSHADERSOURCEPROC)glFP[1]) (f, 1, &fsh, NULL);
((PFNGLCOMPILESHADERPROC)glFP[2])(f);

((PFNGLATTACHSHADERPROC)glFP[4])(p,v);
((PFNGLATTACHSHADERPROC)glFP[4])(p,f);

((PFNGLLINKPROGRAMPROC)glFP[5])(p);
((PFNGLUSEPROGRAMPROC) glFP[6])(p);


}


static PIXELFORMATDESCRIPTOR pfd;

void WINAPI WinMainCRTStartup()
{
      // minimal windows setup code for opengl 
      pfd.cColorBits = pfd.cDepthBits = 32;
      pfd.dwFlags    = PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;

// "HDC hDC" changed 19. April 2007 by benny!weltenkonstrukteur.de
    HDC hDC = GetDC( CreateWindow("edit", 0, WS_POPUP|WS_VISIBLE|WS_MAXIMIZE, 0, 0, 0, 0, 0, 0, 0, 0) );

/*      PVOID hDC= GetDC ( CreateWindow("edit", 0,
                    WS_POPUP|WS_VISIBLE|WS_CLIPSIBLINGS|WS_CLIPCHILDREN|WS_MAXIMIZE,
                    0, 0, 0,0, 0, 0, 0, 0) ); 
*/
      SetPixelFormat ( hDC, ChoosePixelFormat ( hDC, &pfd) , &pfd );
      wglMakeCurrent ( hDC, wglCreateContext(hDC) );

      setShaders();
      ShowCursor(FALSE);

//**********************
// NOW THE MAIN LOOP...
//**********************

    // there is no depth test or clear screen...as we draw in order and cover
    // the whole area of the screen.
    do {
         // we draw 3 spheres using the same shader which is *very* senesitive to radius
         // so we see a 3 fold effect ... a trinity
         glRotatef(3,3,3,3);
         gluSphere(gluNewQuadric(),1.6,200,200);
         gluSphere(gluNewQuadric(),1.04,200,200);
         gluSphere(gluNewQuadric(),0.4,200,200);
         SwapBuffers(hDC);
    } while ( !GetAsyncKeyState(VK_ESCAPE) );   
}

Furthermore, I managed with the help of Crinkler to reduce the original size and still
keep the exe header. Original .com file has 1024 bytes - the crinkler compressed exe is
just 990 bytes ;)

Attached file includes modified source + exe!

P.S:
@chris:
Thanks again for sharing your code. It is really nice to have a working example when beginning
to play with shaders. Cool deed, mate !
Title: Re: 1k Trinity no ordinals
Post by: Jim on April 19, 2007
Thanks Taj!

Jim
Title: Re: 1k Trinity no ordinals
Post by: taj on April 20, 2007
Well done Benny! FYI I can make the shaders in here even smaller, so I think this code could get to 900 bytes! Leaving 100 for another effect...anyway, amazing work Benny. Feel free to put it or a variation on intro inferno if you want. You just became a leet 1k coder!

Hmm a proper timer could be added with these free bytes...

One thing, crinkler is worse at compressing this code. The reason you got better results is that VC++ (not gcc as I used) saves about 70 bytes. Nontheless having an exe is worth the price of the 50 bytes you lost for sure. I actually didnt know this would work...karma++

Chris
Title: Re: 1k Trinity no ordinals
Post by: Jim on April 21, 2007
Benny, is there any chance you could post your vcproj file?
Cheers!

Jim
Title: Re: 1k Trinity no ordinals
Post by: benny! on April 21, 2007
...anyway, amazing work Benny. Feel free to put it or a variation on intro inferno if you want.
You just became a leet 1k coder!

Wow, Chris, thanks a lot. But honestly, I am really right at the beginning watching with an
open mouth how you did all this - so I have to spend a lot of time with reading about shaders
an stuff. But as I said previously, having your running source makes it so much easier to under-
stand and it is so much more motivating for me. Personally, I am really the kind of person who
learns best by examples !!!

...
One thing, crinkler is worse at compressing this code. The reason you got better results is that
VC++ (not gcc as I used) saves about 70 bytes. Nontheless having an exe is worth the price of
the 50 bytes you lost for sure. I actually didnt know this would work...karma++
...

Yup. VC++ really seems to make a good job here and having a "real" exe is something nice ;)
Thx for the karma, mate.

Benny, is there any chance you could post your vcproj file?
...

Np mate. I attached the vcproj file. Use the Release version only !!! Furthermore I have the
glext.h in the project folder because it wasn't installed on my system before ...
Title: Re: 1k Trinity no ordinals
Post by: va!n on April 21, 2007
respect guys....  i think it need long time before i start and understand that stuff.... i would be happy to do my first 4k with a bitmaped font texture and sinusscroller ^^ i am far far far away of that :(     

would be cool to have someone near my location to meet and learn C coding ^^
Title: Re: 1k Trinity no ordinals
Post by: Jim on April 21, 2007
Thanks Benny.  While working on my cracktro competition entry I've been experimenting with removing the CRT, which has caused me a fair amount of grief, especially since I've used some floating point.  Got it working though :D

Jim
Title: Re: 1k Trinity no ordinals
Post by: ninogenio on April 23, 2007
i cant getthis to build ive added the main.cpp and glext files to the project folder but when im trying to build it im getting unresolved linker errors?
Title: Re: 1k Trinity no ordinals
Post by: benny! on April 23, 2007
What linker errors do you get exactly ?

Did you link all additional libs like : opengl32.lib glu32.lib winmm.lib ???
Title: Re: 1k Trinity no ordinals
Post by: ninogenio on April 23, 2007
here we go i used your vcproj file and addedthe main.c and glext.h files.

LINK : warning LNK4044: unrecognized option '/CRINKLER'; ignored
Main.obj : error LNK2001: unresolved external symbol __fltused
C:\Documents and Settings\nino\Desktop\1k-taj-vcproj\Release\4k.exe : fatal error LNK1120: 1 unresolved externals
Build log was saved at "file://c:\Documents and Settings\nino\Desktop\1k-taj-vcproj\Release\BuildLog.htm"
4k - 2 error(s), 1 warning(s)
========== Build: 0 succeeded, 1 faile
Title: Re: 1k Trinity no ordinals
Post by: taj on April 24, 2007
Nino,

Get rid of the first error by adding:
Code: [Select]
#if defined(__cplusplus)
    extern "C" {
#endif
      int _fltused;
#if defined(__cplusplus)
    };
#endif

just below the include files. How Benny doesnt get this error I have no idea! Which version of VC++ are you using Benny?

From the crinkler manual:

Quote
Unfortunately, Visual Studio does not (as of this writing) support
replacing its linker by a different one. So what you have to do is the
following:

- Copy crinkler.exe to your project directory and rename it to
  link.exe. Visual Studio will then find it when it tries to invoke
  the linker. If you are using some other linker with a different
  name, such as the one used with the Intel C++ compiler, call it
  whatever the name of the linker is.

- If you are using Visual Studio 2005, select Tools/Options... and go
  to Projects and Solutions/VC++ Directories. At the top of the list
  for Executable files, add $(SolutionDir). This will make sure that
  the project directory is searched for the linker executable.

- In the Release configuration (or whichever configuration you want to
  enable compression), under Linker/Command Line/Additional Options,
  type in /CRINKLER, along with any other Crinkler options you want to
  set. See the next section for more details on options. If you are
  using Visual Studio 2005, set Linker/Manifest File/Generate Manifest
  to No.

That should solve problem 2...

Benny was telling someone at work that you beat me by 34 bytes and got an exe on your first attempt. He was mightily impressed. So am I!

Chris
Title: Re: 1k Trinity no ordinals
Post by: taj on April 24, 2007
This is turning into a master class on how to write 1ks!
Title: Re: 1k Trinity no ordinals
Post by: benny! on April 24, 2007
@taj:
Adding your code makes my exe 3 bytes bigger ;-) [ from 990 bytes to 993 bytes ].

The reason why I don't get the error is Crinkler, I think. I use Version 1.0a
(January 7, 2007)
. Without using Crinkler I have to add your code, taj. But Crinkler
doesnt seem to need it.

Btw. Using crinkler option /COMPMODE:SLOW even saves 2 more bytes (988 bytes) ;)

Quote
Benny was telling someone at work that you beat me by 34 bytes and got an exe on your first
attempt. He was mightily impressed. So am I!

Cool. Are your working fellows also interesting in scene and creating tiny codes ??? The most ppl
I know doesn't even know that the scene exists and that there are size competitions like 1KB / 4KB.
Title: Re: 1k Trinity no ordinals
Post by: Jim on April 24, 2007
There's nothing to stop you using _fltused as a variable in your program ;)  Save those bytes again!
eg.
Code: [Select]
int _fltused;
#define global_time _fltused
void main(void) //yeah, should be int...
{
global_time = 1;
}

You only get _fltused linker errors if you use floating point (or floating point functions) in your code, it's referenced by VC's linker by default.  If you use crinkler you won't see it.  Just wait 'til you get to _ftol_sse linker errors if you convert a float to an int!

Also, VC2005 sees this loop...
Code: [Select]
char *dst = ...;
size_t size = ...;
int val = ...;
while (size--)
  *dst++ = val;
...and variations on it, and automatically optimizes that to
Code: [Select]
memset(dst, val, size);
which isn't very useful when you haven't linked in the C runtime!  Couldn't find an option to turn that off.  VC2005 likes generating these intrinsics wherever it can.

Jim
Title: Re: 1k Trinity no ordinals
Post by: benny! on April 24, 2007
There's nothing to stop you using _fltused as a variable in your program ;)  Save those bytes again!

lol ... neat !!!
Title: Re: 1k Trinity no ordinals
Post by: ninogenio on April 24, 2007
ahh now i see where you had trouble removing crt jim!

thats nuts that the compiler takes that much control. cheers for theinfo guys ill maybe try and do a 1k now ;)
Title: Re: 1k Trinity no ordinals
Post by: taj on April 24, 2007
Quote

Cool. Are your working fellows also interesting in scene and creating tiny codes ??? The most ppl
I know doesn't even know that the scene exists and that there are size competitions like 1KB / 4KB.

Wll Im their Director so I gave them some lunch time talks on it and now they are quite interested. Wierdly, I left the scene and now my company wants me to write a demo for a set top box for a show in two weeks so I'm now
coding all day a demo for the silliest hardware in town. Weird world.

Chris
Title: Re: 1k Trinity no ordinals
Post by: taj on April 24, 2007

Also, VC2005 sees this loop...
Code: [Select]
char *dst = ...;
size_t size = ...;
int val = ...;
while (size--)
  *dst++ = val;
...and variations on it, and automatically optimizes that to
Code: [Select]
memset(dst, val, size);
which isn't very useful when you haven't linked in the C runtime!  Couldn't find an option to turn that off.  VC2005 likes generating these intrinsics wherever it can.

Jim


Yeah I faced that and got mad at the compiler. The solution is simple though, write the lopp backwards. Yes I know its more bytes but it works, the compiler is dumb enoyugh it cant spot the memcpy if the loop counts up ;-). Well VC++ Express version anyway.

Chris
Title: Re: 1k Trinity no ordinals
Post by: Jim on April 25, 2007
The way I fixed it was to guarantee the size to be filled was a multiple of 4 (since it was 32bit pixels)
So I made it
Code: [Select]
char *dst = ...;
int *idst = (unsigned int *)dst;
size_t size = ...;
int val = ...;
val *= 0x01010101;
size>>=2;
while (size--)
  *idst++ = val;
Like you say, it's very stupid and it doesn't recognise that as 'rep stosd'.

Jim
Title: Re: 1k Trinity no ordinals
Post by: benny! on April 25, 2007
Wll Im their Director so I gave them some lunch time talks on it and now they are quite interested.
Wierdly, I left the scene and now my company wants me to write a demo for a set top box for a
show in two weeks so I'm now coding all day a demo for the silliest hardware in town. Weird world.
...

Thats the weird way of life indeed, Chris ;) ... but with you they have the best man around to do
this job IMHO.


@taj+jim:
Neat tricks you talk about atm. Too much for my little brain right now. But very interesting !!!