Dark Bit Factory & Gravity
PROGRAMMING => C / C++ /C# => Topic started 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..
// 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
-
Here is the executable.
Once again: No ordinals, so can run on any machine that has shader model 2.0+.
-
Props for posting the source :) It's cool.
-
Nice one, and reminds me to start learning how to code those pixel/vertex shaders 8)
-
Rbraz, if you need help just ask me, and Ill happily swap ideas for some help with my assembler ;)
-
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 ).
// 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 !
-
Thanks Taj!
Jim
-
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
-
Benny, is there any chance you could post your vcproj file?
Cheers!
Jim
-
...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 ...
-
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 ^^
-
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
-
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?
-
What linker errors do you get exactly ?
Did you link all additional libs like : opengl32.lib glu32.lib winmm.lib ???
-
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
-
Nino,
Get rid of the first error by adding:
#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:
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
-
This is turning into a master class on how to write 1ks!
-
@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) ;)
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.
-
There's nothing to stop you using _fltused as a variable in your program ;) Save those bytes again!
eg.
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...
char *dst = ...;
size_t size = ...;
int val = ...;
while (size--)
*dst++ = val;
...and variations on it, and automatically optimizes that to
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
-
There's nothing to stop you using _fltused as a variable in your program ;) Save those bytes again!
lol ... neat !!!
-
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 ;)
-
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
-
Also, VC2005 sees this loop...
char *dst = ...;
size_t size = ...;
int val = ...;
while (size--)
*dst++ = val;
...and variations on it, and automatically optimizes that to
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
-
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
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
-
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 !!!