Skip to content

Instantly share code, notes, and snippets.

@yne
Created December 19, 2015 00:17
Show Gist options
  • Save yne/ec160a4cdb987da879f4 to your computer and use it in GitHub Desktop.
Save yne/ec160a4cdb987da879f4 to your computer and use it in GitHub Desktop.
Luminess in pure OpenGL
#include <windows.h>
#include <GL/gl.h>
#include <GL/glext.h>
#include <GL/wglext.h>
#include <sys/time.h>
#define COUNT(A) (sizeof(A)/sizeof(A[0]))
#define BLOC_EXIST (1<<0)
#define BLOC_COLOR (1<<1)
#define BLOC_MIXED (1<<2)
#define BLOC_CLEAR (1<<3)
#define CTRL_UP (1<<0)
#define CTRL_DN (1<<1)
#define CTRL_LT (1<<2)
#define CTRL_RT (1<<3)
typedef enum{
STATE_PLAY,
STATE_QUIT,
STATE_OVER
}States;
typedef struct{
HWND hWnd;
HGLRC hRC;
HDC hDC;
States state;
unsigned texWidth,texHeight,scrWidth,scrHeight;
unsigned tex[7][32*32];
long long grid_update,curr_msec,prev_msec,cblock_update,key_update;
GLuint tex_id;
unsigned ctrl,score,curclear;
unsigned cblock[2][2];
int cblock_x,cblock_y;
unsigned grid[10][16];
int clrLineX;
}GLCtx;
unsigned winkey=0;//find a better link between with WndProc
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){
//GLCtx*ctx=(GLCtx*)GetWindowLongPtr(hWnd, DWLP_USER);
switch (message){
case WM_CREATE:return 0;
case WM_CLOSE:
PostQuitMessage(0);
return 0;
case WM_DESTROY:return 0;
case WM_KEYUP:
switch (wParam){
case VK_UP :winkey &=~CTRL_UP;break;
case VK_DOWN :winkey &=~CTRL_DN;break;
case VK_LEFT :winkey &=~CTRL_LT;break;
case VK_RIGHT:winkey &=~CTRL_RT;break;
}break;
case WM_KEYDOWN:
switch (wParam){
case VK_UP :winkey |= CTRL_UP;break;
case VK_SPACE:
case VK_DOWN :winkey |= CTRL_DN;break;
case VK_LEFT :winkey |= CTRL_LT;break;
case VK_RIGHT:winkey |= CTRL_RT;break;
case VK_ESCAPE:PostQuitMessage(0);break;
}break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
void GLstart(GLCtx*ctx){
GLint iViewport[4];
glGetIntegerv(GL_VIEWPORT, iViewport);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(iViewport[0], iViewport[0]+iViewport[2],iViewport[1]+iViewport[3], iViewport[1], -1, 1);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_LIGHTING_BIT);
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
glGenTextures(1,&(ctx->tex_id));
glBindTexture(GL_TEXTURE_2D,ctx->tex_id);
//ABGR
for(int i=0;i<COUNT(ctx->tex[0]);i++)ctx->tex[0][i] = 0xFFFF0000|((i>>3)<<8);//NORMAL
for(int i=0;i<COUNT(ctx->tex[0]);i++)ctx->tex[1][i] = 0xFF0000FF|((i>>3)<<8);//
for(int i=0;i<COUNT(ctx->tex[0]);i++)ctx->tex[2][i] = 0xFFFF8080|((i>>3)<<8);//MIXED
for(int i=0;i<COUNT(ctx->tex[0]);i++)ctx->tex[3][i] = 0xFF8080FF|((i>>3)<<8);//
for(int i=0;i<COUNT(ctx->tex[0]);i++)ctx->tex[4][i] = 0xFF880000|((i>>3)<<8);//CLARED
for(int i=0;i<COUNT(ctx->tex[0]);i++)ctx->tex[5][i] = 0xFF000088|((i>>3)<<8);//
for(int i=0;i<COUNT(ctx->tex[0]);i++)ctx->tex[6][i] = 0x00FFFFFF|((i&0x1F)<<27);//
glTexImage2D(GL_TEXTURE_2D,0,4,ctx->texWidth,ctx->texWidth*COUNT(ctx->tex),0,GL_RGBA,GL_UNSIGNED_BYTE,ctx->tex);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);
glDisable(GL_LIGHTING);
glDisable(GL_DITHER);
glDisable(GL_BLEND);
glDisable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glEnable(GL_TEXTURE_RECTANGLE_NV);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor3f(1.0f,1.0f,1.0f);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_RECTANGLE_NV, ctx->tex_id);
}
void winEnableOpenGL(GLCtx*ctx){
ctx->hDC = GetDC(ctx->hWnd);
PIXELFORMATDESCRIPTOR pfd;
pfd.nSize = sizeof(pfd);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 24;
pfd.cDepthBits = 16;
pfd.iLayerType = PFD_MAIN_PLANE;
SetPixelFormat(ctx->hDC, ChoosePixelFormat(ctx->hDC, &pfd), &pfd);
ctx->hRC = wglCreateContext(ctx->hDC);
wglMakeCurrent(ctx->hDC, ctx->hRC);
//enable Vsync (if available)
if(strstr(glGetString(GL_EXTENSIONS),"WGL_EXT_swap_control"))
(*(wglGetProcAddress("wglSwapIntervalEXT")))(1);
GLstart(ctx);
}
void GLstop(GLCtx*ctx){
glPopAttrib();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glDeleteTextures(1,&(ctx->tex_id));
}
void winDisableOpenGL(GLCtx*ctx){
GLstop(ctx);
wglMakeCurrent(NULL, NULL);
wglDeleteContext(ctx->hRC);
ReleaseDC(ctx->hWnd, ctx->hDC);
}
void winStartOpenGL(GLCtx*ctx){
MSG msg;
if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)){
if(msg.message==WM_QUIT)ctx->state=STATE_QUIT;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
ctx->ctrl=winkey;
glClear(GL_COLOR_BUFFER_BIT);
glBegin(GL_QUADS);
ctx->curr_msec=GetTickCount();
}
void winStopOpenGL(GLCtx*ctx){
winkey=ctx->ctrl;
glEnd();
SwapBuffers(ctx->hDC);
}
#define graph_init winEnableOpenGL
#define graph_term winDisableOpenGL
#define graph_start winStartOpenGL
#define graph_stop winStopOpenGL
void drawSprite(int tw,int th,int x,int y,unsigned bloc){
y+= (272*2)-(11*32);
x+=((480*2)-(16*32))/2;
int tb=0;
if(bloc&BLOC_MIXED)tb=2;
if(bloc&BLOC_CLEAR)tb=4;
tb+=(bloc&BLOC_COLOR)?1:0;
glTexCoord2i( 0,(tb<<5)+ 0);glVertex2i(x+ 0,y+ 0);
glTexCoord2i(tw,(tb<<5)+ 0);glVertex2i(x+tw,y+ 0);
glTexCoord2i(tw,(tb<<5)+th);glVertex2i(x+tw,y+th);
glTexCoord2i( 0,(tb<<5)+th);glVertex2i(x+ 0,y+th);
}
void drawClearBar(int tw,int th,int x){
int y= (272*2)-(11*32);
x+=((480*2)-(16*32))/2;
glTexCoord2i( 0,(6<<5)+ 0);glVertex2i(x+0,y+ 0);
glTexCoord2i(32,(6<<5)+ 0);glVertex2i(x+8,y+ 0);
glTexCoord2i(32,(6<<5)+32);glVertex2i(x+8,y+th);
glTexCoord2i( 0,(6<<5)+32);glVertex2i(x+0,y+th);
}
int new_cblock(GLCtx*ctx){
ctx->cblock[0][0]=(ctx->prev_msec&1?BLOC_COLOR:0)|BLOC_EXIST;
ctx->cblock[0][1]=(ctx->prev_msec&2?BLOC_COLOR:0)|BLOC_EXIST;
ctx->cblock[1][0]=(ctx->prev_msec&4?BLOC_COLOR:0)|BLOC_EXIST;
ctx->cblock[1][1]=(ctx->prev_msec&8?BLOC_COLOR:0)|BLOC_EXIST;
ctx->cblock_x=16/2 -1;
ctx->cblock_y=-2;//to be out of the grid
ctx->ctrl&=~CTRL_DN;//clear the down button
ctx->cblock_update=ctx->curr_msec;//be gentle with the gravity
if ((ctx->grid[ctx->cblock_y+2][ctx->cblock_x ]&BLOC_EXIST)
|| (ctx->grid[ctx->cblock_y+2][ctx->cblock_x+1]&BLOC_EXIST))
ctx->state=STATE_OVER;
}
int block_down(GLCtx*ctx){
if( ctx->cblock_y>7
|| (ctx->grid[ctx->cblock_y+2][ctx->cblock_x+0]&BLOC_EXIST)
|| (ctx->grid[ctx->cblock_y+2][ctx->cblock_x+1]&BLOC_EXIST)){
//insert_into_grid
for(int y=0;y<2;y++)
for(int x=0;x<2;x++){
ctx->grid[ctx->cblock_y+y][ctx->cblock_x+x]=ctx->cblock[y][x];
}
new_cblock(ctx);
}else{
ctx->cblock_y++;
}
}
void checkQuad(GLCtx*ctx){
for(int y=1;y<10;y++)
for(int x=1;x<16;x++){
ctx->grid[y][x]= ctx->grid[y][x] & ~BLOC_MIXED;
if(!(ctx->grid[y][x]&BLOC_EXIST))continue;
if ((ctx->grid[y][x]&ctx->grid[y-1][x-1]&ctx->grid[y-1][x]&ctx->grid[y][x-1]&BLOC_EXIST)
&&((ctx->grid[y][x]&BLOC_COLOR) == (ctx->grid[y-1][x-1]&BLOC_COLOR))
&&((ctx->grid[y][x]&BLOC_COLOR) == (ctx->grid[y-1][x] &BLOC_COLOR))
&&((ctx->grid[y][x]&BLOC_COLOR) == (ctx->grid[y][x-1] &BLOC_COLOR))
){
ctx->grid[y-1][x-1]|= BLOC_MIXED;
ctx->grid[y-1][x] |= BLOC_MIXED;
ctx->grid[y][x-1] |= BLOC_MIXED;
ctx->grid[y][x] |= BLOC_MIXED;
}
}
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int iCmdShow){
char*name="Glowminess";
RegisterClass(&((WNDCLASS){CS_OWNDC,WndProc,0,0,hInstance,LoadIcon(NULL, IDI_WINLOGO),LoadCursor(NULL,IDC_ARROW),.lpszClassName=name}));
GLCtx ctx={.texWidth=32,.texHeight=32,.scrWidth=480*2,.scrHeight=272*2,.ctrl=0};
ctx.hWnd=CreateWindow(name,"Glowminess",WS_VISIBLE,32,32,ctx.scrWidth,ctx.scrHeight,NULL,NULL,hInstance,NULL);
//SetWindowLongPtr(ctx.hWnd,DWLP_USER,(LONG)(DWORD_PTR)&ctx);
graph_init(&ctx);
while(ctx.state!=STATE_QUIT){
memset(ctx.grid,0,sizeof(ctx.grid));
ctx.state=STATE_PLAY;
new_cblock(&ctx);
ctx.curclear=0;
ctx.score=0;
while(ctx.state==STATE_PLAY){
graph_start(&ctx);
//update the grid with gravity
if(ctx.curr_msec-ctx.grid_update > 200){
ctx.grid_update=ctx.curr_msec;
for(int y=8;y>=0;y--){
for(int x=15;x>=0;x--){
if((ctx.grid[y][x]&BLOC_EXIST) && !(ctx.grid[y+1][x]&BLOC_EXIST)){
ctx.grid[y+1][x]=ctx.grid[y][x];
ctx.grid[y][x]=0;
}
}
}
checkQuad(&ctx);
}
ctx.clrLineX=ctx.curr_msec>>3&0x1FF;
//User inputs
if(ctx.ctrl&CTRL_UP){
ctx.ctrl&=~CTRL_UP;
int cblock[2][2];
memcpy(cblock,ctx.cblock,sizeof(cblock));
ctx.cblock[0][1]=cblock[0][0];
ctx.cblock[1][1]=cblock[0][1];
ctx.cblock[0][0]=cblock[1][0];
ctx.cblock[1][0]=cblock[1][1];
}
if(ctx.ctrl&CTRL_LT){
ctx.ctrl&=~CTRL_LT;
if(ctx.cblock_x >0 && (ctx.cblock_y<-1 || !(ctx.grid[ctx.cblock_y+1][ctx.cblock_x-1]&BLOC_EXIST)))
ctx.cblock_x--;
}
if(ctx.ctrl&CTRL_RT){
ctx.ctrl&=~CTRL_RT;
if(ctx.cblock_x<14 && (ctx.cblock_y<-1 || !(ctx.grid[ctx.cblock_y+1][ctx.cblock_x+2]&BLOC_EXIST)))
ctx.cblock_x++;
}
if(ctx.ctrl&CTRL_DN){
//ctx.ctrl&=~CTRL_DN;
ctx.cblock_update=ctx.curr_msec;
block_down(&ctx);
}
if(ctx.curr_msec-ctx.cblock_update > 700){
ctx.cblock_update=ctx.curr_msec;
block_down(&ctx);
}
//draw the grid
for(int y=0;y<10;y++)
for(int x=0;x<16;x++)
if(ctx.grid[y][x]&BLOC_EXIST)
drawSprite(ctx.texWidth,ctx.texHeight,x<<5,y<<5,ctx.grid[y][x]);
//draw the active block
for(int y=0;y<2;y++)
for(int x=0;x<2;x++)
drawSprite(ctx.texWidth,ctx.texHeight,(x+ctx.cblock_x)<<5,(y+ctx.cblock_y)<<5,ctx.cblock[y][x]);
//draw the clear line
int colclear=0;
for(int y=0,x=ctx.clrLineX>>5;y<10;y++)
if((ctx.grid[y][x]&BLOC_EXIST) && (ctx.grid[y][x]&BLOC_MIXED)){
ctx.grid[y][x]|=BLOC_CLEAR;
ctx.curclear++;
colclear++;
}
//do the clear
if(!colclear && ctx.curclear){
for(int y=0;y<10;y++)
for(int x=0;x<16;x++)
if((ctx.grid[y][x]&BLOC_EXIST) && (ctx.grid[y][x]&BLOC_CLEAR)){
ctx.grid[y][x]=0;
ctx.score++;
printf("%i\n",ctx.score);
}
ctx.curclear=0;
}
drawClearBar(ctx.texWidth,ctx.texHeight*10,ctx.clrLineX);
ctx.prev_msec=ctx.curr_msec;
graph_stop(&ctx);
}
if(ctx.state==STATE_OVER){
char score[128];
sprintf(score,"Total score:\t%u",ctx.score);
int select = MessageBox(ctx.hWnd,score,"GameOver",MB_RETRYCANCEL|MB_DEFBUTTON1);
if(select==IDCANCEL)
ctx.state=STATE_QUIT;
}
}
graph_term(&ctx);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment