From aecb8413d5c68cc19140fa6627a84048c936645d Mon Sep 17 00:00:00 2001 From: zeromus Date: Sat, 6 Sep 2008 21:39:38 +0000 Subject: [PATCH] toon shading infrastructure and a demo implementation --- desmume/ChangeLog | 1 + desmume/src/MMU.c | 17 +++- desmume/src/render3D.c | 5 +- desmume/src/render3D.h | 2 + desmume/src/windows/OGLRender.c | 139 +++++++++++++++++++++++++++++--- 5 files changed, 147 insertions(+), 17 deletions(-) diff --git a/desmume/ChangeLog b/desmume/ChangeLog index 29b2d1141..75eb5014a 100644 --- a/desmume/ChangeLog +++ b/desmume/ChangeLog @@ -37,6 +37,7 @@ - Convert alpha and material values from [0,31] ranges to opengl ranges in a more precise way [zeromus] - Fix a race condition in NDS_3D_Reset and NDS_glInit [zeromus] - Add many of NHerve's improvements into OGLRender because I was trying to fix all the 3d issues. [zeromus] + - Toon shading infrastructure and a demo implementation [zeromus] 0.7.3 -> 0.8 Cocoa: diff --git a/desmume/src/MMU.c b/desmume/src/MMU.c index 7281d6d9f..ee45642ad 100644 --- a/desmume/src/MMU.c +++ b/desmume/src/MMU.c @@ -1291,8 +1291,14 @@ void FASTCALL MMU_write16(u32 proc, u32 adr, u16 val) if((adr >> 24) == 4) { + if(adr >= 0x04000380 && adr <= 0x040003BE) + { + //toon table + ((u16 *)(MMU.MMU_MEM[proc][0x40]))[(adr-0x04000000)>>1] = val; + gpu3D->NDS_3D_UpdateToonTable(&((MMU.MMU_MEM[proc][0x40]))[(0x380)]); + } /* Adress is an IO register */ - switch(adr) + else switch(adr) { case 0x0400035C: { @@ -1948,8 +1954,13 @@ void FASTCALL MMU_write32(u32 proc, u32 adr, u32 val) gpu3D->NDS_3D_CallList(val); } } - else - switch(adr) + else if(adr >= 0x04000380 && adr <= 0x040003BC) + { + //toon table + ((u32 *)(MMU.MMU_MEM[proc][0x40]))[(adr-0x04000000)>>2] = val; + gpu3D->NDS_3D_UpdateToonTable(&((MMU.MMU_MEM[proc][0x40]))[(0x380)]); + } + else switch(adr) { // Alpha test reference value - Parameters:1 case 0x04000340: diff --git a/desmume/src/render3D.c b/desmume/src/render3D.c index 4825ca7c8..b33122a9c 100644 --- a/desmume/src/render3D.c +++ b/desmume/src/render3D.c @@ -31,6 +31,7 @@ long NDS_nullFunc8 (unsigned int index){ return 0; } void NDS_nullFunc9 (int line, unsigned short * DST) { }; void NDS_nullFunc10 (unsigned int mode, unsigned int index, float* dest) {}; // NDS_3D_GetMatrix void NDS_nullFunc11 (unsigned int index, unsigned int* dest) {}; // NDS_glGetLightDirection +void NDS_nullFunc12 (void* v) {} GPU3DInterface gpu3DNull = { NDS_nullFunc1, // NDS_3D_Init @@ -92,7 +93,9 @@ GPU3DInterface gpu3DNull = { NDS_nullFunc3, // NDS_3D_VecTest NDS_nullFunc8, // NDS_3D_GetPosRes - NDS_nullFunc8 // NDS_3D_GetVecRes + NDS_nullFunc8, // NDS_3D_GetVecRes + + NDS_nullFunc12 // NDS_3D_UpdateToonTable }; GPU3DInterface *gpu3D = &gpu3DNull; diff --git a/desmume/src/render3D.h b/desmume/src/render3D.h index dde23a701..fac293c22 100644 --- a/desmume/src/render3D.h +++ b/desmume/src/render3D.h @@ -125,6 +125,8 @@ typedef struct GPU3DInterface long (CALL_CONVENTION* NDS_3D_GetPosRes) (unsigned int index); long (CALL_CONVENTION* NDS_3D_GetVecRes) (unsigned int index); + void (CALL_CONVENTION* NDS_3D_UpdateToonTable) (void* toonTable); + } GPU3DInterface; diff --git a/desmume/src/windows/OGLRender.c b/desmume/src/windows/OGLRender.c index 8770bf513..7e8571493 100644 --- a/desmume/src/windows/OGLRender.c +++ b/desmume/src/windows/OGLRender.c @@ -1,3 +1,5 @@ +//zeromus todo - software calculate whole lighting model + /* Copyright (C) 2006 yopyop Copyright (C) 2006-2007 shash @@ -98,6 +100,17 @@ static const int material_5bit_to_31bit[] = { 0x739CE739, 0x77BDEF7B, 0x7BDEF7BD, 0x7FFFFFFF }; +static const u8 material_5bit_to_8bit[] = { + 0x00, 0x08, 0x10, 0x18, 0x21, 0x29, 0x31, 0x39, + 0x42, 0x4A, 0x52, 0x5A, 0x63, 0x6B, 0x73, 0x7B, + 0x84, 0x8C, 0x94, 0x9C, 0xA5, 0xAD, 0xB5, 0xBD, + 0xC6, 0xCE, 0xD6, 0xDE, 0xE7, 0xEF, 0xF7, 0xFF +}; + +#define RGB16TO32(col,alpha) (((alpha)<<24) | ((((col) & 0x7C00)>>7)<<16) | ((((col) & 0x3E0)>>2)<<8) | (((col) & 0x1F)<<3)) +//make a table out of this: +#define RGB15TO32(col,alpha8) ( ((alpha8)<<24) | (material_5bit_to_8bit[((col)>>10)&0x1F]<<16) | (material_5bit_to_8bit[((col)>>5)&0x1F]<<8) | material_5bit_to_8bit[(col)&0x1F] ) + static unsigned short matrixMode[2] = {GL_PROJECTION, GL_MODELVIEW}; static short mode = 0; @@ -158,6 +171,8 @@ u32 texcache_stop; //u32 texcache_last; GLenum oglTempTextureID[MAX_TEXTURE]; +GLenum oglToonTableTextureID; +u32 toonShader, toonProgram; //================================================= typedef struct @@ -201,6 +216,28 @@ __forceinline void NDS_3D_Reset() texcache_stop=MAX_TEXTURE<<1; } +static void NDS_3D_UpdateToonTable(void* toonTable) { + u16* u16toonTable = (u16*)toonTable; + u32 rgbToonTable[32]; + int i; + for(i=0;i<32;i++) + rgbToonTable[i] = RGB15TO32(u16toonTable[i],255); + + glTexImage1D(GL_TEXTURE_1D, 0, GL_RGB, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, rgbToonTable); +} + +#define OGLEXT(x,y) x y; +#define INITOGLEXT(x,y) y = (x)wglGetProcAddress(#y); + +OGLEXT(PFNGLCREATESHADERPROC,glCreateShader) +OGLEXT(PFNGLGETSHADERSOURCEPROC,glShaderSource) +OGLEXT(PFNGLCOMPILESHADERPROC,glCompileShader) +OGLEXT(PFNGLCREATEPROGRAMPROC,glCreateProgram) +OGLEXT(PFNGLATTACHSHADERPROC,glAttachShader) +OGLEXT(PFNGLLINKPROGRAMPROC,glLinkProgram) +OGLEXT(PFNGLUSEPROGRAMPROC,glUseProgram) +OGLEXT(PFNGLGETSHADERINFOLOGPROC,glGetShaderInfoLog) + char NDS_glInit(void) { int i; @@ -251,7 +288,7 @@ char NDS_glInit(void) glEnable (GL_DEPTH_TEST); glEnable (GL_TEXTURE_2D); - glAlphaFunc (GL_GREATER, 0.1f); + glAlphaFunc (GL_GREATER, 0); glEnable (GL_ALPHA_TEST); glGenTextures (MAX_TEXTURE, &oglTempTextureID[0]); @@ -296,6 +333,53 @@ char NDS_glInit(void) MatrixInit (mtxCurrent[3]); MatrixInit (mtxTemporal); + INITOGLEXT(PFNGLCREATESHADERPROC,glCreateShader) + INITOGLEXT(PFNGLGETSHADERSOURCEPROC,glShaderSource) + INITOGLEXT(PFNGLCOMPILESHADERPROC,glCompileShader) + INITOGLEXT(PFNGLCREATEPROGRAMPROC,glCreateProgram) + INITOGLEXT(PFNGLATTACHSHADERPROC,glAttachShader) + INITOGLEXT(PFNGLLINKPROGRAMPROC,glLinkProgram) + INITOGLEXT(PFNGLUSEPROGRAMPROC,glUseProgram) + INITOGLEXT(PFNGLGETSHADERINFOLOGPROC,glGetShaderInfoLog) + + if(glCreateShader && glShaderSource && glCompileShader && glCreateProgram && glAttachShader && glLinkProgram && glUseProgram && glGetShaderInfoLog) + { + { + glGenTextures (MAX_TEXTURE, &oglToonTableTextureID); + glBindTexture(GL_TEXTURE_1D,oglToonTableTextureID); + glTexParameterf(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP); //clamp so that we dont run off the edges due to 1.0 -> [0,31] math + //do we need to init the toon table? + } + { + char buf[10000]; + const char* toonShaderSource[] = { + "uniform sampler2D tex2; \ + uniform sampler1D tex1; \ + void main() {\ + gl_FragColor = gl_Color; \ + gl_FragColor = texture1D(tex1,gl_FragColor.r/32*31); \ + gl_FragColor *= texture2D(tex2,gl_TexCoord[0].st); \ + }\ + "}; + + //TODO - this should modulate or add depending on whether we are in highlight or toon mode + + toonShader = glCreateShader(GL_FRAGMENT_SHADER); + toonProgram = glCreateProgram(); + + glShaderSource(toonShader, 1, toonShaderSource, 0); + glCompileShader(toonShader); + glGetShaderInfoLog(toonShader,10000,0,buf); + + glAttachShader(toonProgram,toonShader); + glLinkProgram(toonProgram); + + toonShader = 0; + } + } + return 1; } @@ -635,7 +719,9 @@ __forceinline void NDS_glMultMatrix4x4(signed long v) } -#define RGB16TO32(col,alpha) (((alpha)<<24) | ((((col) & 0x7C00)>>7)<<16) | ((((col) & 0x3E0)>>2)<<8) | (((col) & 0x1F)<<3)) + + +//todo - make all color conversions go through a properly spread table!! __forceinline void* memcpy_fast(void* dest, const void* src, size_t count) { @@ -734,6 +820,9 @@ __forceinline void setTexture(unsigned int format, unsigned int texpal) { texcache_count=i; glBindTexture(GL_TEXTURE_2D,texcache[i].id); + if(i==30) { + int zzz=9; + } return; } } @@ -987,17 +1076,16 @@ __forceinline void setTexture(unsigned int format, unsigned int texpal) case 7: //16bpp { unsigned short * map = ((unsigned short *)adr); + unsigned int * dst = (unsigned int *)texMAP; pal = (unsigned short *)(ARM9Mem.texPalSlot[0] + (texturePalette<<4)); for(x = 0; x < imageSize; ++x) { unsigned short c = map[x]; - dst[0] = ((c & 0x1F)<<3); - dst[1] = ((c & 0x3E0)>>2); - dst[2] = ((c & 0x7C00)>>7); - dst[3] = (c>>15)*255; + int alpha = ((c&0x8000)?255:0); + *dst = RGB15TO32(c,alpha); - dst += 4; + dst++; txt_slot_current_size-=2;; if (txt_slot_current_size<=0) { @@ -1076,7 +1164,6 @@ __forceinline void NDS_glBegin(unsigned long v) else { colorRGB[3] = colorAlpha; - glColor4iv ((GLint*)colorRGB); } //non-31 alpha polys are translucent @@ -1137,6 +1224,10 @@ __forceinline void NDS_glBegin(unsigned long v) glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE); } + //handle toon rendering + if(envMode == 2) { + glUseProgram(toonProgram); + } else glUseProgram(0); glDepthMask(enableDepthWrite?GL_TRUE:GL_FALSE); @@ -1162,10 +1253,9 @@ __forceinline void NDS_glEnd (void) __forceinline void NDS_glColor3b(unsigned long v) { - colorRGB[0] = (v&0x1F) << 26; - colorRGB[1] = ((v>>5)&0x1F) << 26; - colorRGB[2] = ((v>>10)&0x1F) << 26; - glColor4iv ((GLint*)colorRGB); + colorRGB[0] = material_5bit_to_31bit[(v&0x1F)]; + colorRGB[1] = material_5bit_to_31bit[((v>>5)&0x1F)]; + colorRGB[2] = material_5bit_to_31bit[((v>>10)&0x1F)]; } static __forceinline void SetVertex() @@ -1187,6 +1277,7 @@ static __forceinline void SetVertex() MatrixMultVec4x4 (mtxCurrent[1], coordTransformed); + glColor4iv ((GLint*)colorRGB); glVertex3fv (coordTransformed); //count the polys and verts @@ -1381,6 +1472,7 @@ __forceinline void NDS_glMaterial0 (unsigned long val) colorRGB[0] = diffuse[0]; colorRGB[1] = diffuse[1]; colorRGB[2] = diffuse[2]; + colorRGB[3] = diffuse[3]; } if (beginCalled) @@ -1596,6 +1688,26 @@ __forceinline void NDS_glNormal(unsigned long v) MatrixMultVec3x3 (mtxCurrent[2], normal); glNormal3fv(normal); + + //HACK: + //calling normal() causes the vertex color to get updated. + //in this case, if no lights are enabled, then the vertex color is merely set to the emission + //ideally we would execute ALL lighting calculations here instead of just this one case. + if(!lightMask) { + colorRGB[0] = emission[0]; + colorRGB[1] = emission[1]; + colorRGB[2] = emission[2]; + if(emission[0] == material_5bit_to_31bit[18]) { + int zzz=9; + } + else if(emission[0] == material_5bit_to_31bit[26]) { + int zzz=9; + } else { + int zzz=9; + } + } + + } __forceinline void NDS_glBoxTest(unsigned long v) @@ -2129,7 +2241,8 @@ GPU3DInterface gpu3Dgl = { NDS_glInit, NDS_glPosTest, NDS_glVecTest, NDS_glGetPosRes, - NDS_glGetVecRes + NDS_glGetVecRes, + NDS_3D_UpdateToonTable };