Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Topics - rain_storm

Pages: [1] 2 3 4 5
1
C / C++ /C# / Floating Point Hacks
« on: October 05, 2014 »
Here are some nifty bithacks for the IEEE floating point format


The infamous Quakes fast inverse square root...
Code: [Select]
float invSqrt(float x)
{
        float xhalf = 0.5f*x;
        union
        {
          float x;
            int i;
        } u;
        u.x = x;
        u.i = 0x5f3759df - (u.i >> 1);
        /* The next line can be repeated any number of times to increase accuracy */
        u.x = u.x * (1.5f - xhalf * u.x * u.x);
        return u.x;
}

// Quakes version
float Q_rsqrt( float number )
{
int i;
float x2, y;
const float threehalfs = 1.5f;

x2 = number * 0.5f;
y = number;
i = *( int* )&y;                         // evil floating point bit level hacking
i = 0x5F3759DF - ( i >> 1 );             // what the f***?

y = *( float* )&i;
y = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration
// y = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration, this can be removed
return y;
}

// Lomonts version
float InvSqrt( float x )
{
float xhalf = 0.5f*x;
int i = *( int* )&x;         // get bits for floating value
i = 0x5F375A86 - ( i >> 1 ); // gives initial guess y0
x = *( float* )&i;           // convert bits back to float
x = x*(1.5f - xhalf*x*x );   // Newton step, repeating increases accuracy
return x;
}
 
rsqrt:
_asm {
rsqrtps xmm0, xmmword ptr [ rcx ] ;
movaps  xmmword ptr [ rcx ], xmm0 ;
ret                               ;
}

sqrthw:
_asm {
rsqrtps xmm0, xmmword ptr [ rcx ] ;
rcpps   xmm0, xmm0                ;
movaps  xmmword ptr [ rcx ], xmm0 ;
ret                               ;
}


Approximate square root (software solution is faster than hardware)
Code: [Select]
float fastsqrt( float n )
{
int i = *( int* )&n;
i -= 1 << 23;
i >>= 1;
i += 1 << 29;
return *( float* )&i;
}


Newton raphson
Code: [Select]
float sqrtNewRapf( float x )
{
float y = sqrtf( x ); // Get approx
// y = ( y*y + x ) / ( 2*y ); // Newton-Raphson as many times as needed
return ( y*y + x ) / ( 2*y );
}

OneAsIntShr1 dd 4 dup ( 0x1FC00000 ) ; OneAsInt >> 1
fastsqrt:
_asm {
movdqa xmm0, xmmword ptr [ rcx ]          ;
psrld  xmm0, 1                            ;
paddd  xmm0, xmmword ptr [ OneAsIntShr1 ] ;
movdqa xmmword ptr [ rcx ], xmm0          ;
ret                                       ;
}

OneAsIntShr1 dd 4 dup ( 0x1FC00000 ) ; OneAsInt >> 1
fastsqrt:
_asm {
movdqa xmm0, xmmword ptr [ rcx ]          ;
psrld  xmm0, 1                            ;
paddd  xmm0, xmmword ptr [ OneAsIntShr1 ] ;

; Newton Raphson
movaps xmm1, xmm0                         ; Place y ( our guess ) into xmm1 for doubling
addps  xmm1, xmm1                         ; double y
mulps  xmm0, xmm0                         ; square y
addps  xmm0, xmmword ptr [ rcx ]          ; add original x
rcpps  xmm1, xmm1                         ; Divide by our 2y
mulps  xmm0, xmm1                         ;

movaps xmmword ptr [ rcx ], xmm0          ; Store result
ret                                       ;
}


Obviously this one simply flips the sign bit
Code: [Select]
_inline float neg( float f )
{
return AsFloat( AsInt( f ) ^ 0x80000000 );
}

fneg:
_asm {
pcmpeqd xmm1, xmm1                ; Get 0x80000000, -0.0 int xmm1
pslld   xmm1, 31                  ;
; loop here down as necessary     ;
movdqa  xmm0, xmmword ptr [ rcx ] ;
pxor    xmm0, xmm1                ;
movdqa  xmmword ptr [ rcx ], xmm0 ;
ret                               ;
}


Log2 can be done in a similar fashion
Code: [Select]
const unsigned int OneAsInt = 0x3F800000;  // 1.0f as int
const float ScaleUp = float( 0x00800000 ); // 8388608.0, 2^23
const float ScaleDown = 1.0f / ScaleUp;

float Log2( float x )
{
return float ( AsInt( x )-OneAsInt )*ScaleDown;
}


OneAsInt  dd 4 dup ( 0x3F800000 ) ; 1.0 bit pattern as int
ScaleDown dd 4 dup ( 0x34000000 ) ; 4 copies of 1.0 / ScaleUp
Log2f:
asm {
movdqa   xmm0, xmmword ptr [ rcx ]       ;
psubd    xmm0, xmmword ptr [ OneAsInt ]  ;
cvtdq2ps xmm0, xmm0                      ; cast to singles
mulps    xmm0, xmmword ptr [ ScaleDown ] ;
movdqa   xmmword ptr [ rcx ], xmm0       ;
ret                                      ;
}


Exponent2 as well
Code: [Select]
float Exp2( float x )
{
return AsFloat( int( x*ScaleUp ) + OneAsInt );
}

OneAsInt  dd 4 dup ( 0x3F800000 ) ; 1.0 bit pattern as int

Pow2f:
_asm {
movdqa   xmm0, xmmword ptr [ rcx ]      ;
movaps   xmm1, xmmword ptr [ rdx ]      ;
psubd    xmm0, xmmword ptr [ OneAsInt ] ;
cvtdq2ps xmm0, xmm0                     ;
mulps    xmm0, xmm1                     ;
cvtps2dq xmm0, xmm0                     ;
paddd    xmm0, xmmword ptr [ OneAsInt ] ;
movaps   xmmword ptr [ rcx ], xmm0      ;
ret                                     ;
}


Faster fmod1
Code: [Select]
#include <math.h>
#include <time.h>
#include <stdio.h>

static volatile float f2 = 0.0f;

float fmod1_fast( const float f )
{
    const int iBits = *( reinterpret_cast< const int* >( &f ) );

    // extract exponent
    const int iExponent = ( ( iBits & 0x7F800000 ) - 0x3F800000 ) >> 23;

    if( iExponent > 23 )
    {
        return 0.0f;
    }

    if( iExponent < 0 )
    {
        return f;
    }

    const int iSignificand = iBits & 0x007FFFFF;

    if( iSignificand == 0 )
    {
        return 0.0f;
    }

    // find the most significant bit of the significand - this can be done by binary search

    /*
    0111 1111 1111 1111 1111 1111

    0111 1111 1111 0000 0000 0000
    7    F    F    0    0    0
    0111 1100 0000 1111 1100 0000
    7    C    0    F    C    0
    0110 0011 1000 1110 0011 1000
    A    3    8    E    3    8
    0001 0010 0100 1001 0010 0100
    1    2    4    9    2    4

    0100 1001 0010 0100 1001 0010
    4    9    2    4    9    2
    */

    int iMSB = ( iSignificand & 0x007FF000 ) ? 11 : 0;
    iMSB += ( iSignificand & 0x007C0FC0 ) ? 6 : 0;
    iMSB += ( iSignificand & 0x00A38E38 ) ? 3 : 0;
    iMSB += ( iSignificand & 0x00124924 ) ? 2 : 0;
    iMSB += ( iSignificand & 0x00492492 ) ? 1 : 0;

    iMSB = 23 - iMSB;

    const int iNewBits = ( ( iSignificand << ( iMSB + iExponent ) ) & 0x007FFFFF ) | ( 0x3F800000 - ( ( ( iMSB ) - iExponent ) << 23 ) );
    const float fPreMod = *reinterpret_cast< const float* >( &iNewBits );
    const float fMod = ( ( iBits & 0x80000000 ) ? ( 1.0f - fPreMod ) : fPreMod ) - static_cast< float > ( 1 << ( iExponent ) );
    const int iNewNewBits = *reinterpret_cast< const int* >( &fMod );
    const int iNewNewNewBits = iNewNewBits - ( ( iExponent << 23 ) & 0x3F800000 );

    const float fMaybeSignFlippedMod =  *reinterpret_cast< const float* >( &iNewNewNewBits );

    return ( fMaybeSignFlippedMod > 0.0f ) ? fMaybeSignFlippedMod : ( 1.0f - -fMaybeSignFlippedMod );
}

2
Basic fire effect as seen at Lodes Site
Produces effects such as the attached exe.

Now I have 64 bytes spare after this basic effect is in place and would like to make use of those bytes by improving the visuals. What options are available, How would I go about adding a coolmap for example?

3
ASM / Raymarching in 512 bytes
« on: April 29, 2012 »
Here's a tiny effect coded using my 512b framework. It's slow as hell and ugly as sin but for some weird reason I'm kinda proud of it. I really hope this runs on Vista/Windows 7 as it's only been tested on XP SP3. Full source has been included along with the tool used to obtain the import function hashes. No compression was used during the making of this effect.

4
General chat / Forum Politics
« on: November 23, 2011 »
Thank God this place doesn't dabble in politics.

By politics I mean all that BS that goes with the elitist mentality. You know what I mean, a few popular members with lots of bandwagon supporters. I'm a member of two forums and was unaware of the bitter feud between the two that has been going on for years. At first both forums were the same community but two popular members had a falling out and it caused a huge rift in the community. Now both sides claim the others are jerks. While I'm lurking there and thinking you're both as bad as each other. Bunch of Elitist noobie bashers.

Anyway's I recently befriended two of the popular guys, one from each side. This has stirred up all those bitter feelings once again. Now I have each of them trying to convince me that the other guy can't be trusted. I'm trying my best to stay out of it but it ain't that easy. So now I'm thinking of just walking away from the whole situation.

That got me thinking of this place. There's never been any kind of issues like that here. The Admins and the Moderators have done a bang up job of keeping this community together. I look back at all the years I've been here and I think I can only remember 1 instance of trolling which lasted all of 1 post before it was kicked to the curb.


5
C / C++ /C# / Drawing directly to a console
« on: October 20, 2011 »
Here's a neat trick I found that allows you to draw directly to a console window (Only tested under XP). This gives you access to a window using only kernel32 and gdi32 no need to link to user32 at all. The trick is to set the console title to a unique string and then get the HWND to the console using FindWindow. I'm interested in seeing if this works on windows7 because win7 requires you to pump the message queue which adds extra function calls.


Code: [Select]
#pragma comment(lib, "kernel32.lib")
#pragma comment(lib, "gdi32.lib")
#undef UNICODE
#undef _UNICODE
#include <windows.h>

const int resx = 256;
const int resy = 256;
int   pixel[resx*resy];
int   t;
HWND  hwnd;
HDC   hdc;
RECT  rc;

void mainCRTStartup(void)
{
static BITMAPINFO bmi = { sizeof(BITMAPINFOHEADER),0,0,1,32 };
SetConsoleTitle("io");
hwnd = FindWindow(NULL, "io");
if (!hwnd) return;
hdc = GetDC(hwnd);
if (!hdc) return;
static PIXELFORMATDESCRIPTOR pfd = { sizeof(PIXELFORMATDESCRIPTOR),
1,PFD_DRAW_TO_WINDOW|PFD_SUPPORT_GDI|PFD_DOUBLEBUFFER,PFD_TYPE_RGBA,
32,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,PFD_MAIN_PLANE,0,0,0,0 };
static int fmt = ChoosePixelFormat(hdc,&pfd);
if (!fmt) return;
if (!SetPixelFormat(hdc,fmt,&pfd)) return;
while (!GetAsyncKeyState(VK_ESCAPE)) {
for (int y = 0; y < resy; y++) {
for (int x = 0; x < resx; x++) {
pixel[x+y*resx] = (x^y)+t;
}
}
GetClientRect(hwnd, &rc);
bmi.bmiHeader.biWidth  = resx;
bmi.bmiHeader.biHeight = resy;
StretchDIBits(hdc,rc.right/2-resx/2,rc.bottom/2-resy/2,resx,resy,
0,0,resx,resy,pixel,&bmi,0,SRCCOPY);
SwapBuffers(hdc);
t++;
}
ReleaseDC(hwnd,hdc);
DestroyWindow(hwnd);
ExitProcess(0);
return;
}

-edit my bad FindWindow requires user32 thought NODEFAULTLIBS was suppose to exclude it apparently it doesn't

6
General chat / Reversing the 6502
« on: October 19, 2011 »
reverse engineering 6502, its illegal opcodes and emulating it at the transistor level,
geek pr0n

[youtube]http://www.youtube.com/watch?v=fWqBmmPQP40[/youtube]

7
Yabasic / WireWorld in 13 lines of code
« on: August 17, 2011 »
WireWorld is a cellular automaton that can simulate electronic components such as Logic Gates. And since Logic Gates are the building blocks of CPU's it's no wonder that some geeks have already built a CPU in WireWorld.

Here is a WireWorld simulator written in 13 lines of ps2yabasic source code. With the limitation that every single line of code should fit within the default size of the emulators editor display, colons are allowed to separate statements within a single line. The horizontal scroll bar remains inactive so I don't make use of that final column either. There isn't much wasted space at the end of the lines so you'd be hard pressed to shave off some lines of code.

controls:
up,down,left,right = move the cursor
cross = toggle state of the selected cell (from void to wire to tail to head)
triangle,circle,square = run the simulator

Code: [Select]
open window 1,1:data 64,51,10,16,32,64,128,4096,8192,16384,32768
data 255,255,0,0,0,127,127,127,255:dim C(641,513),R(3),G(3),B(3)
read W,H,S,U,R,D,L,T,O,C,Q:for i=1 to 3 read R(i),G(i),B(i) next
0:setdispbuf B:B=1-B:setdrawbuf B:for y=1 to H for x=1 to W     
c=C(x,y):setrgb 1,R(c),G(c),B(c):fill box x*S,y*S,x*S-S,y*S-S   
next next:setrgb 1,99,0,0:box X*S,Y*S,X*S-S,Y*S-S:P=peek("port1")
if(and(P,C)=C)C(X,Y)=and(C(X,Y)+1,3):X=X+and(P,R)/R-and(P,L)/L: 
X=min(max(X,1),W):Y=min(max(Y+and(P,D)/D-and(P,U)/U,1),H):F=Q+T+O
if(and(P,F)=0)goto 0:dim T(W,H):for y=1 to H for x=1 to W:N=0:   
for v=y-1 to y+1 for u=x-1 to x+1 if(C(u,v)=3)N=N+1 next next:   
T(x,y)=1:if(C(x,y)=0)then T(x,y)=0 elsif(C(x,y)=2)then T(x,y)=1 
elsif(C(x,y)=3)then T(x,y)=2 elsif(N=1 or N=2)then T(x,y)=3 fi   
next next:for y=0 to H for x=0 to W C(x,y)=T(x,y)next next:goto 0

8
C / C++ /C# / Anyone using the Intel C Compiler?
« on: July 23, 2011 »
I downloaded icc but it doesn't work with Visual Studio Express (only works with the non free versions?). I'm trying to get icc to compile from the commandline but it's not working out for me yet. Just wondering if anyone here has looked into it before I spend too much time trying to figure out the whole commandline interface.

From what I've read icc generates code that is much more optimized than anything else in the feild but only for intel compatible machines. Also I heard rumours that the intel libraries test if the machine is AMD and if so uses the slowest versions of each function.

9
General chat / Wow
« on: July 07, 2011 »
This speaks for itself...
link
site

[youtube]fAsg_xNzhcQ[/youtube]

10
General coding questions / Frame interpolation?
« on: July 05, 2011 »
How would you go about interpolating inbetween frames from a before and after? Best I can think of would be to choose a pixel, take the colour before add the colour after and average the two to create an inbetween. Is there a better solution?

11
Projects / Voxel Engine
« on: June 21, 2011 »
I'm releasing the source code for my voxel engine. It currently uses quadtree subsampling to reduce the number of rays being cast, and the fast voxel traversal algorithm to accelerate those rays which are cast. I'm planning to take on the sparse voxel octree traversal approach if I can manage to pull it off. I'm fairly happy with this as it stands, there are a few things not yet implemented correctly, such as texture mapping in such a way so as to take advantage of the quadtree subsampling, and a proper link list that would allow shapes other than spheres. Still I would like to share the source with others who have some interest in voxels. Voxels are the future make no doubt about it. Polygons have had their day.

Edit - Texture mapping now works better, managed to increase the resolution with no loss in speed. Maximum number of shapes increased to 256. Limited support for discs, capsules and cylinders.

12
Projects / [IN PROGRESS] 512b GDI FrameWork
« on: March 19, 2011 »
Heres a gdi based 512b framework I've been working on. I haven't done much header mangling yet but I've marked out most of the feilds that are safe to play with on my system. It would be a great help if some people could test to see if I have already broken the clean version and if the dirty version is too optimistic. If all goes well you should see a greyscale.

Using this framework I hope to be able to release win32 demos on par with the average 128b DOS releases.

Edit 1 - (OLD) Added current version (352 bytes) tested only on XP
Edit 2 - (OLD) Added example of raycasting in 512 bytes
Edit 3 - (OLD) version 347b
Edit 4 - Latest version 295b

13
C / C++ /C# / Benchmarking looks suspiciously incorrect
« on: February 20, 2011 »
The Fast Inverse Squareroot calculates an approximation of 1.0f/sqrt(x) in
less time than it takes to calculate a floating point division.

By squaring the input the routine can be adapted to calculate 1.0f/sqrt(x*x)
which is effectively calculating the same thing as 1.0f/x, I call this the
Fast Inverse Division. Theres just one snag... the sign bit.

By squaring the input you force the value to be positive. However restoring
the proper sign is a trivial fix which requires neither a comparison nor
inline asm.

Code: [Select]
float InvSqrt(float x) {             // compute 1.0f/sqrt(x)
float xhalf = 0.5f * x;          //
int i = *(int*)&x;               // store floating-point bits in integer
i = 0x5f3759d5 - (i >> 1);       // initial guess for Newton's method
x = *(float*)&i;                 // convert new bits into float
x = x*(1.5f - xhalf*x*x);        // One round of Newton's method
return x;
}

float InvDiv(float n) {               // compute 1.0f/n
int s = (*(int*)&n) & 0x80000000; // extract the sign bit of the input
float x = n*n;                    // square the input
float xhalf = 0.5f * x;           //
int i = *(int*)&x;                // store floating-point bits in integer
i = (0x5f3759d5 - (i >> 1)) | s;  // initial guess for Newton's method and reapply the sign bit
x = *(float*)&i;                  // convert new bits into float
x = x*(1.5f - xhalf*x*x);         // One round of Newton's method
return x;                         //
}

The result is an approximation of 1.0f/n. Now I know that under ideal conditions
division can be computed in close to the same ammount of time as multiplication.
This is possible only when dividing by a power of two inside a heavily optimized
pipeline. But in the real world division is a thing best avoided.

I wanted to stress test this modified routine to see how it really performs. The
problem is that I've never benchmarked accurately before. I usually just apply an
optimization and run. It should become obvious if the optimization was effective.

So first I decided to clock a loop that merely converted an int to a float and
accumulated the result. The time taken to do all that would be subtracted from the
tick count for each test, This should eliminate the time not spent performing the
calculation i wanted to benchmark. Here's what I came up with:

Code: [Select]
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <conio.h>

float InvSqrt(float x) {             // compute 1.0f/sqrt(x)
float xhalf = 0.5f * x;          //
int i = *(int*)&x;               // store floating-point bits in integer
i = 0x5f3759d5 - (i >> 1);       // initial guess for Newton's method
x = *(float*)&i;                 // convert new bits into float
x = x*(1.5f - xhalf*x*x);        // One round of Newton's method
return x;
}

float InvDiv(float n) {               // compute 1.0f/n
int s = (*(int*)&n) & 0x80000000; // extract the sign bit of the input
float x = n*n;                    // square the input
float xhalf = 0.5f * x;           //
int i = *(int*)&x;                // store floating-point bits in integer
i = (0x5f3759d5 - (i >> 1)) | s;  // initial guess for Newton's method and reapply the sign bit
x = *(float*)&i;                  // convert new bits into float
x = x*(1.5f - xhalf*x*x);         // One round of Newton's method
return x;                         //
}

int main(void) {
DWORD oldTick, newTick, numTick, nopTick;
int iterations = 100000000;
float result = 0.0f;

// empty loop
printf("running 100,000,000 iterations of empty loop\n");
oldTick = GetTickCount();
for (int a = 1; a <= iterations; a++) {
float x = float(a);
result += x;
}
newTick = GetTickCount();
nopTick = newTick - oldTick;
printf("  oldTick = 0x%08X (%u)\n", oldTick, oldTick);
printf("  newTick = 0x%08X (%u)\n", newTick, newTick);
printf("  nopTick = 0x%08X (%u)\n", nopTick, nopTick);
printf("\n");

// floating point 1.0f/sqrt(x)
printf("running 100,000,000 iterations of 1.0f/sqrt(x)\n");
oldTick = GetTickCount();
for (int a = 1; a <= iterations; a++) {
float x = 1.0f/sqrt(float(a));
result += x;
}
newTick = GetTickCount();
numTick = newTick - oldTick - nopTick;
printf("  oldTick = 0x%08X (%u)\n", oldTick, oldTick);
printf("  newTick = 0x%08X (%u)\n", newTick, newTick);
printf("  numTick = 0x%08X (%u)\n", numTick, numTick);
printf("\n");

// InvSqrt(x)
printf("running 100,000,000 iterations of InvSqrt(x)\n");
oldTick = GetTickCount();
for (int a = 1; a <= iterations; a++) {
float x = float(a);
float xhalf = 0.5f * x;          //
int i = *(int*)&x;               // store floating-point bits in integer
i = 0x5f3759d5 - (i >> 1);       // initial guess for Newton's method
x = *(float*)&i;                 // convert new bits into float
x = x*(1.5f - xhalf*x*x);        // One round of Newton's method
result += x;
}
newTick = GetTickCount();
numTick = newTick - oldTick - nopTick;
printf("  oldTick = 0x%08X (%u)\n", oldTick, oldTick);
printf("  newTick = 0x%08X (%u)\n", newTick, newTick);
printf("  numTick = 0x%08X (%u)\n", numTick, numTick);
printf("\n");

// floating point 1.0f/x
printf("running 100,000,000 iterations of 1.0f/x\n");
oldTick = GetTickCount();
for (int a = 1; a <= iterations; a++) {
float x = 1.0f/float(a);
result += x;
}
newTick = GetTickCount();
numTick = newTick - oldTick - nopTick;
printf("  oldTick = 0x%08X (%u)\n", oldTick, oldTick);
printf("  newTick = 0x%08X (%u)\n", newTick, newTick);
printf("  numTick = 0x%08X (%u)\n", numTick, numTick);
printf("\n");

// InvSqrt(x)
printf("running 100,000,000 iterations of InvDiv(x)\n");
oldTick = GetTickCount();
for (int a = 1; a <= iterations; a++) {
float n = float(a);
int s = (*(int*)&n) & 0x80000000; // extract the sign bit of the input
float x = n*n;                    // square the input
float xhalf = 0.5f * x;           //
int i = *(int*)&x;                // store floating-point bits in integer
i = (0x5f3759d5 - (i >> 1)) | s;  // initial guess for Newton's method and reapply the sign bit
x = *(float*)&i;                  // convert new bits into float
x = x*(1.5f - xhalf*x*x);         // One round of Newton's method
result += x;
}
newTick = GetTickCount();
numTick = newTick - oldTick - nopTick;
printf("  oldTick = 0x%08X (%u)\n", oldTick, oldTick);
printf("  newTick = 0x%08X (%u)\n", newTick, newTick);
printf("  numTick = 0x%08X (%u)\n", numTick, numTick);
printf("\n");

_getch();
printf("%u\n", result);
return 0;
}

results
Code: [Select]
2609 ticks per 100,000,000 iterations 1.0f/sqrt(x)
 391 ticks per 100,000,000 iterations InvSqrt(x)
 422 ticks per 100,000,000 iterations 1.0f/x
1203 ticks per 100,000,000 iterations InvDiv(x)

that cant be correct can it? You'd think it would take more than a 422 ticks to
compute 100,000,000 divisions

14
ASM / MultiThreading Problem
« on: January 27, 2011 »
I seem to be having some trouble getting to grips with multithreading.

My idea was to spawn one thread for drawing, another for generating audio. The drawing thread works well, the problem is that I can't get Saida's synth to work in a multithreading prog.

The synth works just fine if you simply call the proc but it will not work if I launch the synth as a thread, nor will it work if I launch the draw proc as a thread then call synth directly.

It's probably something ridiculously simple but I just can't see it. Can anybody spot what I'm missing here?

stdcall
Code: [Select]
format  pe console
 entry   start
 include "windows.inc"

 RESX = 0x100
 RESY = 0x0C0

 data import
      library kernel32, "kernel32",\
              user32,   "user32",\
              gdi32,    "gdi32",\
              winmm,    "winmm.dll"
      include "api\kernel32.inc"
      include "api\user32.inc"
      include "api\gdi32.inc"
      import  winmm,\
              midiOutClose,    "midiOutClose",\
              midiOutOpen,     "midiOutOpen",\
              midiOutShortMsg, "midiOutShortMsg"
 end  data

 proc start
      ;xor     edi, edi
      ;invoke  GetModuleHandle, edi, edi
      ;invoke  CreateWindowEx, edi, edit, edi, WS_POPUP+WS_VISIBLE+WS_MAXIMIZE, edi, edi, edi, edi, edi, edi, eax, edi
      ;mov     [hWnd], eax
      ;invoke  GetDC, [hWnd]
      ;mov     [hDC], eax
      ;invoke  ShowCursor;, 0  ; <- was the second param for GetModuleHandle(0,wtf)
      ;invoke  CreateThread, 0, 0, draw, 0, 0, idDraw
      ;mov     [hDraw], eax
      ;invoke  CreateThread, 0, 0, synth, 0, 0, idSynth
      ;mov     [hSynth], eax
       call   synth
;.main:
     ;invoke  GetAsyncKeyState, VK_ESCAPE
     ;test    eax, eax
     ;jz      .main

     ;invoke  CloseHandle, [hSynth]
     ;invoke  CloseHandle, [hDraw]
     ;invoke  midiOutClose, [hMidi]
     ;invoke  ReleaseDC, [hWnd], [hDC]
     ;invoke  DestroyWindow, [hWnd]
     ;invoke  ExitProcess, 0
      ret
 endp

 proc draw
      invoke  GetClientRect, [hWnd], rc
      invoke  StretchDIBits, [hDC], 0, 0, [rc.right], [rc.bottom], 0, 0, RESX, RESY, pixel, bmi, 0, SRCCOPY
      inc     [curFrame]
      mov     edi, pixel
      mov     ecx, RESX*RESY
 .draw:
      movzx   eax, cl
      dec     al
      xor     al, ch
      add     eax, [curFrame]
      stosd
      loop    .draw
      jmp     draw
 endp

 proc synth
      xor     eax, eax
      mov     edi, hMidi
      push    eax
      push    eax
      push    eax
      dec     eax
      invoke  midiOutOpen, edi, eax

 .reset:
      mov     esi, edi
      lodsd

 .load:
      lodsb
      xchg    ah, al
      xor     ebx, ebx
      add     bl, ah
      jz      .reset
      shr     bl, 5
      and     ebx, 00000011b
      mov     bx, word [edi-16+(2*ebx)]
      mov     ecx, eax
      and     ax, 0001111100000000b
      or      eax, 00000000011111110010000010010001b
      push    eax
      push    dword [edi]
      xchg    eax, ecx
      sahf
      mov     eax, [edi-8]
      js      .done
      mov     eax, [edi-4]
 .done:
      push    eax
      push    dword [edi]
      invoke  midiOutShortMsg
      invoke  midiOutShortMsg
      invoke  Sleep, ebx
      jmp     .load
 endp

 lengths     dw 240, 1, 0, 0
 Instruments dd 12594625, 12594625
 hMidi       dd ?
 db 10000101b,10101001b,10001100b
 db 10000000b,10101001b,10001100b
 db 10000101b,10101001b,10001100b
 db 10000000b,10101001b,10001100b
 db 10000101b,10101001b,10001100b
 db 10000000b,10101001b,10001100b
 db 10000101b,10000000b,10000010b
 db 10000100b,00000000b

 edit     db "edit",0
 bmi      dd 40,RESX,RESY,0x200001,?,?,?,?,?,?,?,?,?,?
 hWnd     dd ?
 hDC      dd ?
 rc       RECT ?,?,?,?
 curFrame dd ?

 idDraw   dd ?
 hDraw    dd ?
 idSynth  dd ?
 hSynth   dd ?

 pixel    dd RESX*RESY dup ?

Multithreaded
Code: [Select]

 format  pe console
 entry   start
 include "windows.inc"

 RESX = 0x100
 RESY = 0x0C0

 data import
      library kernel32, "kernel32",\
              user32,   "user32",\
              gdi32,    "gdi32",\
              winmm,    "winmm.dll"
      include "api\kernel32.inc"
      include "api\user32.inc"
      include "api\gdi32.inc"
      import  winmm,\
              midiOutClose,    "midiOutClose",\
              midiOutOpen,     "midiOutOpen",\
              midiOutShortMsg, "midiOutShortMsg"
 end  data

 proc start
       xor     edi, edi
       invoke  GetModuleHandle, edi, edi
       invoke  CreateWindowEx, edi, edit, edi, WS_POPUP+WS_VISIBLE+WS_MAXIMIZE, edi, edi, edi, edi, edi, edi, eax, edi
       mov     [hWnd], eax
       invoke  GetDC, [hWnd]
       mov     [hDC], eax
       invoke  ShowCursor;, 0  ; <- was the second param for GetModuleHandle(0,wtf)
       invoke  CreateThread, 0, 0, draw, 0, 0, idDraw
       mov     [hDraw], eax
       invoke  CreateThread, 0, 0, synth, 0, 0, idSynth
       mov     [hSynth], eax
      ;call   synth
 .main:
      invoke  GetAsyncKeyState, VK_ESCAPE
      test    eax, eax
      jz      .main

      invoke  CloseHandle, [hSynth]
      invoke  CloseHandle, [hDraw]
      invoke  midiOutClose, [hMidi]
      invoke  ReleaseDC, [hWnd], [hDC]
      invoke  DestroyWindow, [hWnd]
      invoke  ExitProcess, 0
      ret
 endp

 proc draw
      invoke  GetClientRect, [hWnd], rc
      invoke  StretchDIBits, [hDC], 0, 0, [rc.right], [rc.bottom], 0, 0, RESX, RESY, pixel, bmi, 0, SRCCOPY
      inc     [curFrame]
      mov     edi, pixel
      mov     ecx, RESX*RESY
 .draw:
      movzx   eax, cl
      dec     al
      xor     al, ch
      add     eax, [curFrame]
      stosd
      loop    .draw
      jmp     draw
 endp

 proc synth
      xor     eax, eax
      mov     edi, hMidi
      push    eax
      push    eax
      push    eax
      dec     eax
      invoke  midiOutOpen, edi, eax

 .reset:
      mov     esi, edi
      lodsd

 .load:
      lodsb
      xchg    ah, al
      xor     ebx, ebx
      add     bl, ah
      jz      .reset
      shr     bl, 5
      and     ebx, 00000011b
      mov     bx, word [edi-16+(2*ebx)]
      mov     ecx, eax
      and     ax, 0001111100000000b
      or      eax, 00000000011111110010000010010001b
      push    eax
      push    dword [edi]
      xchg    eax, ecx
      sahf
      mov     eax, [edi-8]
      js      .done
      mov     eax, [edi-4]
 .done:
      push    eax
      push    dword [edi]
      invoke  midiOutShortMsg
      invoke  midiOutShortMsg
      invoke  Sleep, ebx
      jmp     .load
 endp

 lengths     dw 240, 1, 0, 0
 Instruments dd 12594625, 12594625
 hMidi       dd ?
 db 10000101b,10101001b,10001100b
 db 10000000b,10101001b,10001100b
 db 10000101b,10101001b,10001100b
 db 10000000b,10101001b,10001100b
 db 10000101b,10101001b,10001100b
 db 10000000b,10101001b,10001100b
 db 10000101b,10000000b,10000010b
 db 10000100b,00000000b

 edit     db "edit",0
 bmi      dd 40,RESX,RESY,0x200001,?,?,?,?,?,?,?,?,?,?
 hWnd     dd ?
 hDC      dd ?
 rc       RECT ?,?,?,?
 curFrame dd ?

 idDraw   dd ?
 hDraw    dd ?
 idSynth  dd ?
 hSynth   dd ?

 pixel    dd RESX*RESY dup ?

15
General chat / Need a host for a new site
« on: December 28, 2009 »
I need a host for a new site and Im new to all this but I trust what every one on this board has to say so first I go to you guys and ask where do I start looking for someone to host my site?. I plan to have primarily graphics and text and a few exe down loads. I am tempted to add a forum at a later stage (later than launch date anyways ; )

But the thing that I am most worried about is quality of service. I have seen what a desastrious job hostpapa did to to this site. I dont want anything like that happening to my baby.

I am targeting the 100 - 150 sterling per annum bracket as my upper limit. and want the best quality that I can get at this price. so Anyone here have any suggestions.

16
Yabasic / Lighting Effect
« on: October 29, 2009 »
This is a nice lighting effect applied to a cube, It uses the surface normals to calculate the lighting.

Press up/down/left/right to move the light vertically/horizontally
Press triangle/cross to move the light in/out

Code: [Select]
//
// Demonstration of how to calculate lighting effects
// An improvement to this meathod would be to use a
// per vertex lighting algorithm
//
FALSE = 0
TRUE = 1
DEBUG = FALSE

label Init
    open window 640, 512
    window origin "cc"

    UP = 16
    RT = 32
    DN = 64
    LF = 128
    TR = 8192
    EX = 16384

label Vertices
    read verts
    dim px(verts), py(verts), pz(verts)
    dim nx(verts), ny(verts), nz(verts)
    dim tx(verts), ty(verts)
    for i = 0 to verts
        read px(i), py(i), pz(i)
    next i

label Polygons
    read polys
    dim p1(polys), p2(polys), p3(polys), p4(polys)
    for i = 0 to polys
        read p1(i), p2(i), p3(i), p4(i)
    next i

label Colours
    dim r1(polys), g1(polys), b1(polys)
    dim r2(polys), g2(polys), b2(polys)
    dim r3(polys), g3(polys), b3(polys)
    dim r4(polys), g4(polys), b4(polys)
    for i = 0 to polys
        read r1(i), g1(i), b1(i)
        read r2(i), g2(i), b2(i)
        read r3(i), g3(i), b3(i)
        read r4(i), g4(i), b4(i)
    next i

label Lighting
    litX = -64.0
    litY = -64.0
    litZ = -64.0
    Ambient = 0.1

label Camera
    camX = 0.0000
    camY = 0.0000
    camZ = -256.0
    Aspect = 512.0

label Loop
    c = peek("port1")
    if (and(c, UP) > 0) litY = litY - 1.0
    if (and(c, RT) > 0) litX = litX + 1.0
    if (and(c, DN) > 0) litY = litY + 1.0
    if (and(c, LF) > 0) litX = litX - 1.0
    if (and(c, TR) > 0) litZ = litZ + 1.0
    if (and(c, EX) > 0) litZ = litZ - 1.0
    rotX = rotX + 0.0100
    rotY = rotY + 0.0020
    rotZ = rotZ + 0.0003
    Rotate(rotX, rotY, rotZ, -camX,-camY,-camZ)
    Render()
    goto Loop

sub Rotate(rx,ry,rz, ox,oy,oz)
    local cx,cy,cz, sx,sy,sz, px,py,pz, nx,ny,nz, tx,ty,tz
    cx = cos(rx)
    sx = sin(rx)
    cy = cos(ry)
    sy = sin(ry)
    cz = cos(rz)
    sz = sin(rz)
    for i = 0 to verts
        px = px(i)
        py = py(i)
        pz = pz(i)
        nx = cz*px + sz*py
        ny = cz*py - sz*px
        nz = cy*pz + sy*nx
        tx = cy*nx - sy*pz
        ty = cx*ny + sx*nz
        tz = cx*nz - sx*ny
        nx(i) = tx
        ny(i) = ty
        nz(i) = tz
        tz = Aspect/(tz+oz)
        tx(i) = (tx+ox)*tz
        ty(i) = (ty+oy)*tz
    next i
end sub

sub Render()
    setdispbuf draw
    draw = 1 - draw
    setdrawbuf draw
    setrgb 1, 015, 015, 063
    setrgb 2, 015, 015, 063
    setrgb 3, 063, 063, 255
    gtriangle -320.0,256.00 to 320.00,256.00 to 320.00,-256.0
    setrgb 2, 063, 063, 255
    gtriangle -320.0,256.00 to -320.0,-256.0 to 320.00,-256.0
   
    //
    // Draw a white circle for the light
    if (litZ >= 0.0) then
        setrgb 1, 255, 255, 255
        lz = Aspect/(litZ-camZ)
        lx = litX*lz
        ly = litY*lz
        fill circle lx, ly, 10
    endif
   
    for i = 0 to polys
        x1 = tx(p1(i))
        y1 = ty(p1(i))
        x2 = tx(p2(i))
        y2 = ty(p2(i))
        x3 = tx(p3(i))
        y3 = ty(p3(i))
        x4 = tx(p4(i))
        y4 = ty(p4(i))
        cp = (x1-x2)*(y3-y2) - (x3-x2)*(y1-y2)
        if (cp > 0) then
            nx1 = nx(p1(i))
            ny1 = ny(p1(i))
            nz1 = nz(p1(i))
            nx2 = nx(p2(i))
            ny2 = ny(p2(i))
            nz2 = nz(p2(i))
            nx3 = nx(p3(i))
            ny3 = ny(p3(i))
            nz3 = nz(p3(i))
            nx4 = nx(p4(i))
            ny4 = ny(p4(i))
            nz4 = nz(p4(i))
            //
            // Calculate the midpoint of polygon
            cx = (nx1+nx2+nx3+nx4)*0.25
            cy = (ny1+ny2+ny3+ny4)*0.25
            cz = (nz1+nz2+nz3+nz4)*0.25
            //
            // Calculate the normal vector using cross-product
            nx = (nz1-nz2)*(ny3-ny2) - (ny1-ny2)*(nz3-nz2)
            ny = (nx1-nx2)*(nz3-nz2) - (nz1-nz2)*(nx3-nx2)
            nz = (ny1-ny2)*(nx3-nx2) - (nx1-nx2)*(ny3-ny2)
            //
            // Calculate the lighting vector
            lx = litX - cx
            ly = litY - cy
            lz = litZ - cz
            //
            // Calculate length of the normal & lighting vectors
            n = 1.0/sqrt(nx*nx + ny*ny + nz*nz)
            l = 1.0/sqrt(lx*lx + ly*ly + lz*lz)
            //
            // Normalise the normal & lighting vectors
            nx = n*nx
            ny = n*ny
            nz = n*nz
            lx = l*lx
            ly = l*ly
            lz = l*lz
            //
            // Calculate dot-product of normal & lighting vectors
            dp = max(Ambient, nx*lx + ny*ly + nz*lz + Ambient)
            //
            // Scale colour channels by dot-product
            setrgb 1, r1(i)*dp, g1(i)*dp, b1(i)*dp
            setrgb 2, r2(i)*dp, g2(i)*dp, b2(i)*dp
            setrgb 3, r3(i)*dp, g3(i)*dp, b3(i)*dp
            gtriangle x1, y1 to x2, y2 to x3, y3
            setrgb 2, r4(i)*dp, g4(i)*dp, b4(i)*dp
            gtriangle x1, y1 to x4, y4 to x3, y3
            //
            // Debug view of surface normals & midpoints
            if (DEBUG = TRUE) then
            pz = Aspect/(nz*60-camZ)
            py = ny*pz*60
            px = nx*pz*60
            cz = Aspect/(cz-camZ)
            cy = cy*cz
            cx = cx*cz
            setrgb 1, 255, 255, 000
            line cx, cy to px, py
            line x1, y1 to px, py
            line x2, y2 to px, py
            line x3, y3 to px, py
            line x4, y4 to px, py
            line x1, y1 to cx, cy
            line x2, y2 to cx, cy
            line x3, y3 to cx, cy
            line x4, y4 to cx, cy
            line x1, y1 to x2, y2
            line x2, y2 to x3, y3
            line x3, y3 to x4, y4
            line x4, y4 to x1, y1
            endif
        endif
    next i
    //
    // Draw a white circle for the light
    if (litZ < 0.0) then
        setrgb 1, 255, 255, 255
        lz = Aspect/(litZ-camZ)
        lx = litX*lz
        ly = litY*lz
        fill circle lx, ly, 10
    endif
    //
    // Display data
    setrgb 1, 255, 255, 255
    text -300,-240, "ROTX : " + str$(rotX)
    text -300,-220, "ROTY : " + str$(rotY)
    text -300,-200, "ROTZ : " + str$(rotZ)
    text -300,-180, "LITX : " + str$(litX)
    text -300,-160, "LITY : " + str$(litY)
    text -300,-140, "LITZ : " + str$(litZ)
end sub

label Model
    data 7 // verts
    data -30.0,30.00,30.00
    data -30.0,-30.0,30.00
    data -30.0,30.00,-30.0
    data -30.0,-30.0,-30.0
    data 30.00,30.00,30.00
    data 30.00,-30.0,30.00
    data 30.00,30.00,-30.0
    data 30.00,-30.0,-30.0
    data 5 // polys
    data 2,0,4,6
    data 7,5,1,3
    data 3,1,0,2
    data 6,4,5,7
    data 0,1,5,4
    data 3,2,6,7
    data 000,255,000, 255,000,000, 000,000,255, 200,200,200
    data 063,063,063, 255,000,255, 255,255,000, 000,255,255
    data 000,255,255, 255,255,000, 255,000,000, 000,255,000
    data 200,200,200, 000,000,255, 255,000,255, 063,063,063
    data 255,000,000, 255,255,000, 255,000,255, 000,000,255
    data 000,255,255, 000,255,000, 200,200,200, 063,063,063
 

17
General coding questions / Need a modern DOS Debugger
« on: October 02, 2009 »
Can anyone here suggest a good DOS debugger that can handle the newer instructions (x87, mmx, sse, etc.)

I have searched and searched but anything I find is either too primitive to be of any serious use or is incapable of handling the latest instructions.

18
General chat / 256 bytes of shock and awe
« on: September 23, 2009 »
http://www.pouet.net/prod.php?which=53816
top of the month over at  pouet just brings a tear to my eye. Rrrola is just the dogs bollucks when it comes to 256 byters. I think I found my personal icon.


19
ASM / GL Textures But No Colour
« on: September 18, 2009 »
Im dabbling around with openGL and textured quads. The problem is that I can't get anything but greyscale. No matter what values I set for the colour channels its always the least significant byte that gets applied to red, green and blue. Anyone know what I'm doing wrong here.

Code: [Select]
format  pe gui 4.0
 entry   WinMainCRTStartup
 include 'win32a.inc'
 include 'opengl32.inc'

 section '.idata' import data readable writable

      library kernel32, 'kernel32.dll',\
              user32,   'user32.dll',\
              gdi32,    'gdi32.dll',\
              opengl32, 'opengl32.dll',\
              glu32,    'glu32.dll'

      include 'api\kernel32.inc'
      include 'api\user32.inc'
      include 'api\gdi32.inc'
      include 'api\opengl32.inc'
      include 'api\glu32.inc'

 section '.data' data readable writable

      edit      db 'edit',0
      pfd       PIXELFORMATDESCRIPTOR
      hDC       dd ?
      hInstance dd ?

      initTime  dd ?
      thisTime  dd ?
      scrX      dd ?
      scrY      dd ?

      TW = 0x100 ; TextureWidth
      TH = 0x100 ; TextureHeight
      texX      dd ?
      texY      dd ?
      texture   db TW*TH*3 dup ?

 section '.code' code readable executable

      proc WinMainCRTStartup
           invoke  GetTickCount
           mov     [initTime], eax
           invoke  GetSystemMetrics, SM_CXSCREEN
           mov     [scrX], eax
           invoke  GetSystemMetrics, SM_CYSCREEN
           mov     [scrY], eax
           stdcall CreateGLWindow, [scrX], [scrY], 0x20
           stdcall GenerateTextures, TW, TH, texture

      .Main:
           invoke  GetTickCount
           sub     eax, [initTime]
           mov     [thisTime], eax

           invoke  glClear, GL_DEPTH_BUFFER_BIT or GL_COLOR_BUFFER_BIT
           invoke  glRotatef, 1.0, 0.0, 0.0, 1.0
           invoke  glScalef, 1.0, 1.0, 1.0
           stdcall TexturedQuad, -0.5, -0.5, 0.0,  1.0, 1.0,\
                                  0.5, -0.5, 0.0,  1.0, 0.0,\
                                  0.5,  0.5, 0.0,  0.0, 0.0,\
                                 -0.5,  0.5, 0.0,  0.0, 1.0
           invoke  SwapBuffers, [hDC]

           invoke  GetAsyncKeyState, VK_ESCAPE
           or      eax, eax
           jz      .Main

           invoke  glDeleteTextures, 1, texture
           invoke  ExitProcess, NULL
      endp

      proc CreateGLWindow width, height, bpp
           mov     al, byte [bpp]

           mov     [pfd.nSize], sizeof.PIXELFORMATDESCRIPTOR
           mov     [pfd.nVersion], 0x01
           mov     [pfd.dwFlags], PFD_SUPPORT_OPENGL or PFD_DOUBLEBUFFER
           mov     [pfd.iPixelType], PFD_TYPE_RGBA
           mov     [pfd.cColorBits], al
           mov     [pfd.cRedBits], 0x00
           mov     [pfd.cRedShift], 0x00
           mov     [pfd.cGreenBits], 0x00
           mov     [pfd.cGreenShift], 0x00
           mov     [pfd.cBlueBits], 0x00
           mov     [pfd.cBlueShift], 0x00
           mov     [pfd.cAlphaBits], 0x00
           mov     [pfd.cAlphaShift], 0x00
           mov     [pfd.cAccumBits], 0x00
           mov     [pfd.cAccumRedBits], 0x00
           mov     [pfd.cAccumGreenBits], 0x00
           mov     [pfd.cAccumBlueBits], 0x00
           mov     [pfd.cAccumAlphaBits], 0x00
           mov     [pfd.cDepthBits], al
           mov     [pfd.cStencilBits], 0x00
           mov     [pfd.cAuxBuffers], 0x00
           mov     [pfd.iLayerType], 0x00
           mov     [pfd.bReserved], 0x00
           mov     [pfd.dwLayerMask], 0x00
           mov     [pfd.dwVisibleMask], 0x00
           mov     [pfd.dwDamageMask], 0x00

           invoke  CreateWindowExA, 0, edit, 0, WS_POPUP or WS_VISIBLE, 0, 0, [width], [height], 0, 0, 0, 0
           invoke  GetDC, eax
           mov     [hDC], eax
           invoke  ChoosePixelFormat, [hDC], pfd
           invoke  SetPixelFormat, [hDC], eax, pfd
           invoke  wglCreateContext, [hDC]
           invoke  wglMakeCurrent, [hDC], eax
           invoke  ShowCursor, FALSE
           ret
      endp

      proc GenerateTextures width, height, lpPixels
           push    dword [height]
           pop     [texY]
           push    dword [width]
           pop     [texX]
           mov     edi, [lpPixels]
           mov     edx, [height]
           dec     edx
      .loopY:
           mov     ecx, [width]
           dec     ecx
      .loopX:

           mov     eax, ecx
           or      eax, edx
           stosb

           mov     eax, ecx
           and     eax, edx
           stosb

           mov     eax, ecx
           xor     eax, edx
           stosb

           dec     ecx
           jns    .loopX
           dec     edx
           jns     .loopY

           invoke  glEnable, GL_TEXTURE_2D
           ;invoke  glGenTextures, 1, texture
           ;invoke  glBindTexture, GL_TEXTURE_2D, eax
           ;invoke  glTexParameterf, GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR
           ;invoke  glTexParameterf, GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST
           invoke  gluBuild2DMipmaps, GL_TEXTURE_2D, 1, [texX], [texY], GL_RGB, GL_UNSIGNED_BYTE, texture
           ret
      endp

      proc TexturedQuad x1, y1, z1, u1, v1,\
                        x2, y2, z2, u2, v2,\
                        x3, y3, z3, u3, v3,\
                        x4, y4, z4, u4, v4

           invoke  glBegin, GL_QUADS
           invoke  glTexCoord2f, [u1], [v1]
           invoke  glVertex3f,   [x1], [y1], [z1]
           invoke  glTexCoord2f, [u2], [v2]
           invoke  glVertex3f,   [x2], [y2], [z2]
           invoke  glTexCoord2f, [u3], [v3]
           invoke  glVertex3f,   [x3], [y3], [z3]
           invoke  glTexCoord2f, [u4], [v4]
           invoke  glVertex3f,   [x4], [y4], [z4]
           invoke  glEnd
           ret
      endp

20
General chat / Demoscene book
« on: August 18, 2009 »
http://www.demoscenebook.com/index.html

Anyone have this? It's sold out atm but it looks like it's worth a read.

Pages: [1] 2 3 4 5