How to draw sprites using a palette in GM Studio:Vertex Shader (GLSL ES)
Code:
//
// Simple passthrough vertex shader
//
attribute vec3 in_Position; // (x,y,z)
//attribute vec3 in_Normal; // (x,y,z) unused in this shader.
attribute vec4 in_Colour; // (r,g,b,a)
attribute vec2 in_TextureCoord; // (u,v)
varying vec2 v_vTexcoord;
varying vec4 v_vColour;
void main()
{
vec4 object_space_pos = vec4( in_Position.x, in_Position.y, in_Position.z, 1.0);
gl_Position = gm_Matrices[MATRIX_WORLD_VIEW_PROJECTION] * object_space_pos;
v_vColour = in_Colour;
v_vTexcoord = in_TextureCoord;
}
Fragment or pixel Shader (GLSL ES)
Code:
// Simple passthrough fragment shader
//
varying vec2 v_vTexcoord;
varying vec4 v_vColour;
uniform sampler2D Palette;
//size of palette image, in pixels.
uniform vec2 PaletteImageSize;
void main()
{
//Use 255 if not intel.
//texture2D() returns colors in range [0,1]. Put them back into the range[0,255],
//where the value refers to the exact pixel X,Y.
vec4 indexPixel = texture2D( gm_BaseTexture, v_vTexcoord) * vec4(256);
//Comment out these conditionals if not intel.
if(indexPixel.r >= 128.0)indexPixel.r--;
if(indexPixel.g >= 128.0)indexPixel.g--;
if(indexPixel.b >= 128.0)indexPixel.b--;
if(indexPixel.a >= 128.0)indexPixel.a--;
//convert the pixel coords into UV coords in the range [0,1],
// as expected by texture2D()
vec2 paletteCoords = vec2(indexPixel.x,indexPixel.y) / PaletteImageSize;
//issue: gamemaker stores all images into a "Texture page",
//thus, the above coords are incorrect.
//fix: externally loaded palette images
gl_FragColor = texture2D( Palette, paletteCoords);
}
Notes:
"uniform sampler2D Palette" refer to a sampler texture that is an
externally loaded sprites since GM will auto batch sprites into a "Texture Page". When that happens, GM will change the UV coords to something unexpected. But, I need to know the exact UV coords of the palette image, so instead I externally load them to reserve the original UV coords.
The drawn sprite (gm_BaseTexture) is an
indexed sprite, where each pixel's color.r (indexPixel.x) refers to the x coordinate of the correct color within the palette (domain [0,255]) and color.g (indexPixel.y) refers to the y coordinate of the correct color within the palette (domain [0,255]).
___
I'm just typing this up for other people and for my own reference. If you ever move to GM Studio or any other graphics library (OpenGL, Direct X), you can still refer to the above to draw sprites with arbitrary palettes.
[b]How to draw sprites using a palette in GM Studio:[/b]
Vertex Shader (GLSL ES)
[code]
//
// Simple passthrough vertex shader
//
attribute vec3 in_Position; // (x,y,z)
//attribute vec3 in_Normal; // (x,y,z) unused in this shader.
attribute vec4 in_Colour; // (r,g,b,a)
attribute vec2 in_TextureCoord; // (u,v)
varying vec2 v_vTexcoord;
varying vec4 v_vColour;
void main()
{
vec4 object_space_pos = vec4( in_Position.x, in_Position.y, in_Position.z, 1.0);
gl_Position = gm_Matrices[MATRIX_WORLD_VIEW_PROJECTION] * object_space_pos;
v_vColour = in_Colour;
v_vTexcoord = in_TextureCoord;
}[/code]
Fragment or pixel Shader (GLSL ES)
[code]// Simple passthrough fragment shader
//
varying vec2 v_vTexcoord;
varying vec4 v_vColour;
uniform sampler2D Palette;
//size of palette image, in pixels.
uniform vec2 PaletteImageSize;
void main()
{
//Use 255 if not intel.
//texture2D() returns colors in range [0,1]. Put them back into the range[0,255],
//where the value refers to the exact pixel X,Y.
vec4 indexPixel = texture2D( gm_BaseTexture, v_vTexcoord) * vec4(256);
//Comment out these conditionals if not intel.
if(indexPixel.r >= 128.0)indexPixel.r--;
if(indexPixel.g >= 128.0)indexPixel.g--;
if(indexPixel.b >= 128.0)indexPixel.b--;
if(indexPixel.a >= 128.0)indexPixel.a--;
//convert the pixel coords into UV coords in the range [0,1],
// as expected by texture2D()
vec2 paletteCoords = vec2(indexPixel.x,indexPixel.y) / PaletteImageSize;
//issue: gamemaker stores all images into a "Texture page",
//thus, the above coords are incorrect.
//fix: externally loaded palette images
gl_FragColor = texture2D( Palette, paletteCoords);
}[/code]
Notes:
"uniform sampler2D Palette" refer to a sampler texture that is an [i]externally[/i] loaded sprites since GM will auto batch sprites into a "Texture Page". When that happens, GM will change the UV coords to something unexpected. But, I need to know the exact UV coords of the palette image, so instead I externally load them to reserve the original UV coords.
The drawn sprite (gm_BaseTexture) is an [i]indexed[/i] sprite, where each pixel's color.r (indexPixel.x) refers to the x coordinate of the correct color within the palette (domain [0,255]) and color.g (indexPixel.y) refers to the y coordinate of the correct color within the palette (domain [0,255]).
___
I'm just typing this up for other people and for my own reference. If you ever move to GM Studio or any other graphics library (OpenGL, Direct X), you can still refer to the above to draw sprites with arbitrary palettes.