Created
May 20, 2018 03:51
-
-
Save WilliamBundy/c316b4f03dea09aefe95e28cc282421d to your computer and use it in GitHub Desktop.
Some gl rendering stuff out of context
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Graphics */ | |
#define Shader_MaxAttribs 16 | |
#define Shader_MaxUniforms 16 | |
struct wShaderComponent | |
{ | |
string name; | |
i32 loc, divisor; | |
i32 type, count; | |
usize ptr; | |
}; | |
enum { | |
//Shader kinds | |
wShader_Vertex, | |
wShader_Frag, | |
//Component kinds | |
wShader_Attrib, | |
wShader_Uniform, | |
//Component types | |
wShader_Float, | |
wShader_Double, | |
//Passed with glVertexAttributeIPointer | |
wShader_Int, | |
wShader_Short, | |
wShader_Byte, | |
//Passed with normalize set to true | |
wShader_NormalizedInt, | |
wShader_NormalizedShort, | |
wShader_NormalizedByte, | |
//Converted to floats on the GPU | |
wShader_FloatInt, | |
wShader_FloatShort, | |
wShader_FloatByte, | |
wShader_Mat22, | |
wShader_Mat33, | |
wShader_Mat44 | |
}; | |
enum { | |
wRenderBatch_Arrays, | |
wRenderBatch_Elements, | |
wRenderBatch_ArraysInstanced, | |
wRenderBatch_ElementsInstanced, | |
}; | |
enum { | |
wRenderBatch_BlendNormal, | |
wRenderBatch_BlendPremultiplied, | |
wRenderBatch_BlendNone, | |
}; | |
enum { | |
wRenderBatch_Triangles, | |
wRenderBatch_TriangleStrip, | |
wRenderBatch_TriangleFan, | |
wRenderBatch_Lines, | |
wRenderBatch_LineStrip, | |
wRenderBatch_LineLoop | |
}; | |
struct wShader | |
{ | |
u32 vert, frag, program; | |
i32 targetVersion; | |
i32 defaultDivisor; | |
i32 stride; | |
i32 attribCount, uniformCount; | |
wShaderComponent attribs[Shader_MaxAttribs]; | |
wShaderComponent uniforms[Shader_MaxUniforms]; | |
}; | |
struct wTexture | |
{ | |
i64 w, h; | |
u8* pixels; | |
u32 glIndex; | |
}; | |
struct wRenderBatch | |
{ | |
wTexture* texture; | |
wShader* shader; | |
u32 vao, vbo; | |
isize elementSize, elementCount, instanceSize; | |
isize indicesCount; | |
isize startOffset; | |
void* data; | |
u32* indices; | |
i32 clearOnDraw; | |
i32 renderCall; | |
i32 blend; | |
i32 scissor; | |
f32 scissorRect[4]; | |
i32 primitiveMode; | |
}; | |
void wInitShader(wShader* shader, i32 stride); | |
i32 wAddAttribToShader(wShader* shader, wShaderComponent* attrib); | |
wShaderComponent* wCreateAttrib(wShader* shader, | |
string name, i32 type, i32 count, usize ptr); | |
i32 wAddUniformToShader(wShader* shader, wShaderComponent* uniform); | |
wShaderComponent* wCreateUniform(wShader* shader, | |
string name, i32 type, i32 count, usize ptr); | |
i32 wFinalizeShader(wShader* shader); | |
i32 wAddSourceToShader(wShader* shader, string src, i32 kind); | |
void wRemoveSourceFromShader(wShader* shader, i32 kind); | |
void wDeleteShaderProgram(wShader* shader); | |
void wInitBatch(wRenderBatch* batch, | |
wTexture* texture, wShader* shader, | |
i32 renderCall, i32 primitiveMode, | |
isize elementSize, isize instanceSize, | |
void* data, u32* indices); | |
void wConstructBatchGraphicsState(wRenderBatch* batch); | |
void wDrawBatch(wState* state, wRenderBatch* batch, void* uniformData); | |
void wSetBatchScissorRect(wRenderBatch* batch, i32 enabled, f32 x, f32 y, f32 w, f32 h); | |
//wTexture* wLoadTexture(wWindow* window, string filename, wMemoryArena* arena); | |
i32 wInitTexture(wTexture* texture, void* data, isize size); | |
void wUploadTexture(wTexture* texture); | |
void wInitShader(wShader* shader, i32 stride) | |
{ | |
shader->vert = 0; | |
shader->frag = 0; | |
shader->program = 0; | |
shader->targetVersion = 33; | |
shader->defaultDivisor = 0; | |
shader->stride = stride; | |
shader->attribCount = 0; | |
shader->uniformCount = 0; | |
} | |
i32 wAddAttribToShader(wShader* shader, wShaderComponent* attrib) | |
{ | |
if(shader->attribCount < 0) shader->attribCount = 0; | |
if(shader->attribCount >= Shader_MaxAttribs) { | |
return 0; | |
} | |
shader->attribs[shader->attribCount++] = *attrib; | |
return 1; | |
} | |
wShaderComponent* wCreateAttrib(wShader* shader, | |
string name, i32 type, i32 count, usize ptr) | |
{ | |
if(shader->attribCount < 0) shader->attribCount = 0; | |
if(shader->attribCount >= Shader_MaxAttribs) { | |
return NULL; | |
} | |
wShaderComponent* c = shader->attribs + shader->attribCount; | |
c->name = name; | |
c->loc = shader->attribCount; | |
c->divisor = shader->defaultDivisor; | |
c->type = type; | |
c->count = count; | |
c->ptr = ptr; | |
shader->attribCount++; | |
return c; | |
} | |
i32 wAddUniformToShader(wShader* shader, wShaderComponent* uniform) | |
{ | |
if(shader->uniformCount < 0) shader->uniformCount = 0; | |
if(shader->uniformCount >= Shader_MaxUniforms) { | |
return 0; | |
} | |
shader->uniforms[shader->uniformCount++] = *uniform; | |
return 0; | |
} | |
wShaderComponent* wCreateUniform(wShader* shader, | |
string name, i32 type, i32 count, usize ptr) | |
{ | |
if(shader->uniformCount < 0) shader->uniformCount = 0; | |
if(shader->uniformCount >= Shader_MaxUniforms) { | |
return NULL; | |
} | |
wShaderComponent* c = shader->uniforms + shader->uniformCount; | |
c->name = name; | |
c->loc = shader->attribCount; | |
c->divisor = shader->defaultDivisor; | |
c->type = type; | |
c->count = count; | |
c->ptr = ptr; | |
shader->uniformCount++; | |
return c; | |
} | |
i32 wFinalizeShader(wShader* shader) | |
{ | |
if(shader->program != 0) { | |
wLogError(0, "Error: attempting to re-compile shader\n"); | |
wLogError(0, "Delete old program first before trying\n"); | |
return 0; | |
} | |
shader->program = glCreateProgram(); | |
glAttachShader(shader->program, shader->vert); | |
if(shader->targetVersion < 33) | |
for(isize i = 0; i < shader->attribCount; ++i) { | |
shader->attribs[i].loc = i; | |
glBindAttribLocation(shader->program, i, shader->attribs[i].name); | |
} | |
glAttachShader(shader->program, shader->frag); | |
glLinkProgram(shader->program); | |
i32 success = 1; | |
glGetProgramiv(shader->program, GL_LINK_STATUS, &success); | |
if(!success) { | |
char log[4096]; | |
i32 logSize = 0; | |
glGetProgramInfoLog(shader->program, 4096, &logSize, log); | |
wLogError(0, "\n=====Shader Program Link Log=====\n%s\n\n", log); | |
return 0; | |
} | |
glUseProgram(shader->program); | |
for(isize i = 0; i < shader->uniformCount; ++i) { | |
shader->uniforms[i].loc = glGetUniformLocation( | |
shader->program, shader->uniforms[i].name); | |
} | |
glUseProgram(0); | |
return 1; | |
} | |
void wDeleteShaderProgram(wShader* shader) | |
{ | |
wRemoveSourceFromShader(shader, wShader_Vertex); | |
wRemoveSourceFromShader(shader, wShader_Frag); | |
glDeleteProgram(shader->program); | |
shader->program = 0; | |
} | |
void wRemoveSourceFromShader(wShader* shader, i32 kind) | |
{ | |
if(kind == wShader_Vertex) { | |
glDetachShader(shader->program, shader->vert); | |
glDeleteShader(shader->vert); | |
shader->vert = 0; | |
} else if(kind == wShader_Frag) { | |
glDetachShader(shader->program, shader->frag); | |
glDeleteShader(shader->frag); | |
shader->frag = 0; | |
} | |
} | |
i32 wAddSourceToShader(wShader* shader, string src, i32 kind) | |
{ | |
i32 glkind = -1; | |
if(kind == wShader_Vertex) { | |
glkind = GL_VERTEX_SHADER; | |
if(shader->vert != 0) { | |
wLogError(0, "Error: re-adding vertex source\n"); | |
return 0; | |
} | |
} else if(kind == wShader_Frag) { | |
glkind = GL_FRAGMENT_SHADER; | |
if(shader->frag != 0) { | |
wLogError(0, "Error: re-adding fragment source\n"); | |
return 0; | |
} | |
} else { | |
//TODO(will): error logging | |
return 0; | |
} | |
u32 obj = glCreateShader(glkind); | |
glShaderSource(obj, 1, &src, NULL); | |
glCompileShader(obj); | |
i32 success = 1; | |
glGetShaderiv(obj, GL_COMPILE_STATUS, &success); | |
if(!success) { | |
char log[4096]; | |
i32 logSize = 0; | |
glGetShaderInfoLog(obj, 4096, &logSize, log); | |
wLogError(0, "\n=====%s Shader Compile Log=====\n%s\n\n", | |
kind == wShader_Vertex ? "Vertex" : "Frag", log); | |
wLogError(0, "\n=====Source====\n%s\n=====End=====\n\n", src); | |
return 0; | |
} | |
if(kind == wShader_Vertex) { | |
shader->vert = obj; | |
} else if(kind == wShader_Frag) { | |
shader->frag = obj; | |
} | |
return 1; | |
} | |
void wInitBatch(wRenderBatch* batch, | |
wTexture* texture, wShader* shader, | |
i32 renderCall, i32 primitiveMode, | |
isize elementSize, isize instanceSize, | |
void* data, u32* indices) | |
{ | |
memset(batch, 0, sizeof(wRenderBatch)); | |
batch->texture = texture; | |
batch->shader = shader; | |
batch->renderCall = renderCall; | |
batch->primitiveMode = primitiveMode; | |
batch->elementSize = elementSize; | |
batch->instanceSize = instanceSize; | |
batch->data = data; | |
batch->indices = indices; | |
} | |
static | |
u32 transformOpenGLTypes(u32 in) | |
{ | |
switch(in) { | |
case wShader_NormalizedInt: | |
return GL_INT; | |
case wShader_NormalizedShort: | |
return GL_SHORT; | |
case wShader_NormalizedByte: | |
return GL_UNSIGNED_BYTE; | |
case wShader_Float: | |
return GL_FLOAT; | |
case wShader_Double: | |
return GL_DOUBLE; | |
case wShader_FloatInt: | |
return GL_INT; | |
case wShader_FloatShort: | |
return GL_SHORT; | |
case wShader_FloatByte: | |
return GL_UNSIGNED_BYTE; | |
case wShader_Int: | |
return GL_INT; | |
case wShader_Short: | |
return GL_SHORT; | |
case wShader_Byte: | |
return GL_UNSIGNED_BYTE; | |
default: | |
return GL_FLOAT; | |
} | |
} | |
void wConstructBatchGraphicsState(wRenderBatch* batch) | |
{ | |
wShader* shader = batch->shader; | |
glUseProgram(shader->program); | |
if(shader->targetVersion > 21) { | |
glGenVertexArrays(1, &batch->vao); | |
glBindVertexArray(batch->vao); | |
} | |
glGenBuffers(1, &batch->vbo); | |
glBindBuffer(GL_ARRAY_BUFFER, batch->vbo); | |
i32 attribTypes[] = { | |
GL_FLOAT, GL_DOUBLE, | |
GL_INT, GL_SHORT, GL_UNSIGNED_BYTE, | |
GL_INT, GL_SHORT, GL_UNSIGNED_BYTE, | |
GL_INT, GL_SHORT, GL_UNSIGNED_BYTE, | |
0, 0, 0 | |
}; | |
for(isize i = 0; i < shader->attribCount; ++i) { | |
wShaderComponent* c = shader->attribs + i; | |
i32 isNormalized = 0; | |
#if WPL_EMSCRIPTEN | |
u32 type = transformOpenGLTypes(c->type); | |
#else | |
u32 type = attribTypes[c->type - wShader_Float]; | |
#endif | |
glEnableVertexAttribArray(c->loc); | |
if(glVertexAttribDivisor) glVertexAttribDivisor(c->loc, c->divisor); | |
switch(c->type) { | |
case wShader_NormalizedInt: | |
case wShader_NormalizedShort: | |
case wShader_NormalizedByte: | |
isNormalized = 1; | |
case wShader_Float: | |
case wShader_Double: | |
case wShader_FloatInt: | |
case wShader_FloatShort: | |
case wShader_FloatByte: | |
//printf("%s %d -> %x\n", c->name, c->type - wShader_Float, type); | |
glVertexAttribPointer( | |
c->loc, | |
c->count, | |
type, | |
isNormalized, | |
shader->stride, | |
(void*)c->ptr); | |
break; | |
case wShader_Int: | |
case wShader_Short: | |
case wShader_Byte: | |
glVertexAttribIPointer( | |
c->loc, | |
c->count, | |
type, | |
shader->stride, | |
(void*)c->ptr); | |
break; | |
default: | |
break; | |
} | |
} | |
if(batch->shader->targetVersion > 21) { | |
glBindVertexArray(0); | |
} | |
} | |
void wSetBatchScissorRect(wRenderBatch* batch, i32 enabled, f32 x, f32 y, f32 w, f32 h) | |
{ | |
batch->scissor = enabled; | |
batch->scissorRect[0] = x; | |
batch->scissorRect[1] = y; | |
batch->scissorRect[2] = w; | |
batch->scissorRect[3] = h; | |
} | |
void wDrawBatch(wState* state, wRenderBatch* batch, void* uniformData) | |
{ | |
//TODO(will) Add options for other common OpenGL things | |
// ie: depthfunc, culling, stencil/scissor | |
// | |
// Problem: a lot of these are quite powerful and rely on several | |
// calls. Either I lock this all down to a few combinations or just | |
// expose the API to the user. Right now we only do blend, and only | |
// very simple blending at that. | |
wShader* shader = batch->shader; | |
glUseProgram(shader->program); | |
if(batch->scissor) { | |
glEnable(GL_SCISSOR_TEST); | |
f32* s = batch->scissorRect; | |
glScissor(s[0], state->height - s[1] - s[3], s[2], s[3]); | |
} | |
if(batch->blend == wRenderBatch_BlendNormal) { | |
glEnable(GL_BLEND); | |
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |
} else if(batch->blend == wRenderBatch_BlendPremultiplied) { | |
glEnable(GL_BLEND); | |
glBlendEquation(GL_FUNC_ADD); | |
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); | |
} else if(batch->blend == wRenderBatch_BlendNone) { | |
glDisable(GL_BLEND); | |
} | |
if(uniformData) { | |
i32 uniformType[] = { | |
wShader_Float, 0, | |
wShader_Int, 0, 0, 0, 0, 0, 0, 0, 0, | |
wShader_Mat22, wShader_Mat33, wShader_Mat44 | |
}; | |
for(isize i = 0; i < shader->uniformCount; ++i) { | |
wShaderComponent* c = shader->uniforms + i; | |
u32 type = uniformType[c->type - wShader_Float]; | |
f32* uptrf = (f32*)((usize)uniformData + c->ptr); | |
i32* uptri = (i32*)((usize)uniformData + c->ptr); | |
switch(type) { | |
case 0: | |
break; | |
case wShader_Float: | |
switch(c->count) { | |
case 1: | |
glUniform1f(c->loc, uptrf[0]); | |
break; | |
case 2: | |
glUniform2f(c->loc, uptrf[0], uptrf[1]); | |
break; | |
case 3: | |
glUniform3f(c->loc, uptrf[0], uptrf[1], uptrf[2]); | |
break; | |
case 4: | |
glUniform4f(c->loc, | |
uptrf[0], uptrf[1], uptrf[2], uptrf[3]); | |
break; | |
default: | |
break; | |
} | |
break; | |
case wShader_Int: | |
switch(c->count) { | |
case 1: | |
glUniform1i(c->loc, uptri[0]); | |
break; | |
case 2: | |
glUniform2i(c->loc, uptri[0], uptri[1]); | |
break; | |
case 3: | |
glUniform3i(c->loc, uptri[0], uptri[1], uptri[2]); | |
break; | |
case 4: | |
glUniform4i(c->loc, | |
uptri[0], uptri[1], uptri[2], uptri[3]); | |
break; | |
default: | |
break; | |
} | |
break; | |
case wShader_Mat44: | |
glUniformMatrix4fv(c->loc, c->count, 0, uptrf); | |
break; | |
case wShader_Mat33: | |
glUniformMatrix3fv(c->loc, c->count, 0, uptrf); | |
break; | |
case wShader_Mat22: | |
glUniformMatrix2fv(c->loc, c->count, 0, uptrf); | |
break; | |
default: | |
break; | |
} | |
} | |
} | |
if(glBindVertexArray) { | |
glBindVertexArray(batch->vao); | |
} | |
u32 hint; | |
if(batch->clearOnDraw) { | |
hint = GL_STREAM_DRAW; | |
} else { | |
hint = GL_DYNAMIC_DRAW; | |
} | |
glBindBuffer(GL_ARRAY_BUFFER, batch->vbo); | |
glBufferData(GL_ARRAY_BUFFER, | |
batch->elementSize * batch->elementCount, | |
batch->data, | |
hint); | |
if( batch->renderCall == wRenderBatch_Elements || | |
batch->renderCall == wRenderBatch_ElementsInstanced) { | |
glBufferData(GL_ELEMENT_ARRAY_BUFFER, | |
batch->indicesCount * sizeof(u32), | |
batch->indices, | |
hint); | |
} | |
glBindTexture(GL_TEXTURE_2D, batch->texture->glIndex); | |
u32 primitive; | |
switch(batch->primitiveMode) { | |
case wRenderBatch_Triangles: | |
primitive = GL_TRIANGLES; | |
break; | |
case wRenderBatch_TriangleStrip: | |
primitive = GL_TRIANGLE_STRIP; | |
break; | |
case wRenderBatch_TriangleFan: | |
primitive = GL_TRIANGLE_FAN; | |
break; | |
case wRenderBatch_Lines: | |
primitive = GL_LINES; | |
break; | |
case wRenderBatch_LineStrip: | |
primitive = GL_LINE_STRIP; | |
break; | |
case wRenderBatch_LineLoop: | |
primitive = GL_LINE_LOOP; | |
break; | |
default: | |
primitive = GL_TRIANGLES; | |
} | |
switch(batch->renderCall) { | |
case wRenderBatch_Arrays: | |
glDrawArrays(primitive, batch->startOffset, batch->elementCount); | |
break; | |
case wRenderBatch_Elements: | |
glDrawElements(primitive, batch->elementCount, GL_UNSIGNED_INT, | |
(void*)(batch->startOffset * sizeof(u32))); | |
break; | |
case wRenderBatch_ArraysInstanced: | |
glDrawArraysInstanced( | |
primitive, | |
batch->startOffset, | |
batch->instanceSize, | |
batch->elementCount); | |
break; | |
case wRenderBatch_ElementsInstanced: | |
glDrawElementsInstanced(primitive, | |
batch->elementCount, | |
GL_UNSIGNED_INT, | |
(void*)(batch->startOffset * sizeof(u32)), | |
batch->instanceSize); | |
break; | |
default: | |
break; | |
} | |
if(batch->clearOnDraw) { | |
//TODO(will) this might not work with the ElementsInstanced path | |
// the docs aren't clear as to which part of the call is the | |
// instance/element count imo | |
batch->elementCount = 0; | |
} | |
if(batch->scissor) { | |
glDisable(GL_SCISSOR_TEST); | |
} | |
} | |
void wUploadTexture(wTexture* texture) | |
{ | |
glGenTextures(1, &texture->glIndex); | |
glBindTexture(GL_TEXTURE_2D, texture->glIndex); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, | |
texture->w, texture->h, 0, | |
GL_RGBA, GL_UNSIGNED_BYTE, | |
texture->pixels); | |
glGenerateMipmap(GL_TEXTURE_2D); | |
glBindTexture(GL_TEXTURE_2D, 0); | |
} | |
#define STB_IMAGE_IMPLEMENTATION | |
#define STBI_ONLY_PNG | |
#define STBI_NO_STDIO | |
#define STBI_NO_HDR | |
#define STBI_NO_LINEAR | |
#define STBI_ASSERT(x) | |
#include "thirdparty/stb_image.h" | |
i32 wInitTexture(wTexture* texture, void* data, isize size) | |
{ | |
i32 w=0, h=0, bpp=0; | |
u8* pixels = stbi_load_from_memory(data, size, &w, &h, &bpp, STBI_rgb_alpha); | |
if(w == 0 || h == 0) { | |
wLogError(0, "Error: Unable to parse image\n"); | |
return 0; | |
} | |
texture->w = w; | |
texture->h = h; | |
texture->pixels = pixels; | |
texture->glIndex = -1; | |
return 1; | |
} | |
#ifdef wplRenderExample | |
struct Sprite | |
{ | |
u32 flags; | |
u32 color; | |
union { | |
struct {f32 x, y;}; | |
Vec2 pos; | |
}; | |
f32 z; | |
f32 angle; | |
union { | |
struct {f32 w, h;}; | |
Vec2 size; | |
}; | |
union { | |
struct {f32 cx, cy;}; | |
Vec2 center; | |
}; | |
union { | |
struct{i16 tx, ty, tw, th;}; | |
Rect2i texture; | |
}; | |
}; | |
struct SpriteBatch | |
{ | |
wRenderBatch batch; | |
SpriteHandle* handles; | |
Sprite* sprites; | |
Sprite* sprites2; | |
isize count, capacity; | |
union { | |
struct {f32 x, y;}; | |
Vec2 pos; | |
}; | |
f32 vw, vh; | |
f32 scale; | |
u32 tint; | |
f32 itw, ith; | |
}; | |
void createGraphicsDependencies() | |
{ | |
isize textureSize = 0; | |
game.textureFile = wCreateHotFile(&game.window, "assets/art.png"); | |
game.texture = wArenaPush(game.arena, sizeof(wTexture)); | |
wInitTexture(game.texture, game.textureFile->data, game.textureFile->size); | |
wUploadTexture(game.texture); | |
game.vertShader = wCreateHotFile(&game.window, "assets/GL33_vert.glsl"); | |
game.fragShader = wCreateHotFile(&game.window, "assets/GL33_frag.glsl"); | |
game.vertShader->replaceBadSpaces = 1; | |
game.fragShader->replaceBadSpaces = 1; | |
wLogError(0, "frag size: %zd\nvert size: %zd\ntex size %zd\n", | |
game.fragShader->size, | |
game.vertShader->size, | |
0); | |
game.shader = wArenaPush(game.arena, sizeof(wShader)); | |
wInitShader(game.shader, sizeof(Sprite)); | |
game.shader->defaultDivisor = 1; | |
wCreateAttrib(game.shader, | |
"vFlags", wShader_Int, 1, offsetof(Sprite, flags)); | |
wCreateAttrib(game.shader, | |
"vColor", wShader_NormalizedByte, 4, offsetof(Sprite, color)); | |
wCreateAttrib(game.shader, | |
"vPos", wShader_Float, 3, offsetof(Sprite, x)); | |
wCreateAttrib(game.shader, | |
"vAngle", wShader_Float, 1, offsetof(Sprite, angle)); | |
wCreateAttrib(game.shader, | |
"vSize", wShader_Float, 2, offsetof(Sprite, w)); | |
wCreateAttrib(game.shader, | |
"vCenter", wShader_Float, 2, offsetof(Sprite, cx)); | |
wCreateAttrib(game.shader, | |
"vTexture", wShader_FloatShort, 4, offsetof(Sprite, tx)); | |
wCreateUniform(game.shader, | |
"uOffset", wShader_Float, 2, offsetof(SpriteBatch, x)); | |
wCreateUniform(game.shader, | |
"uViewport", wShader_Float, 2, offsetof(SpriteBatch, vw)); | |
wCreateUniform(game.shader, | |
"uScale", wShader_Float, 1, offsetof(SpriteBatch, scale)); | |
wCreateUniform(game.shader, | |
"uTint", wShader_NormalizedByte, 4, offsetof(SpriteBatch, tint)); | |
wCreateUniform(game.shader, | |
"uInvTextureSize", wShader_Float, 2, offsetof(SpriteBatch, itw)); | |
wAddSourceToShader(game.shader, game.vertShader->data, wShader_Vertex); | |
wAddSourceToShader(game.shader, game.fragShader->data, wShader_Frag); | |
wFinalizeShader(game.shader); | |
} | |
SpriteBatch* createSpriteBatch(isize cap, wMemoryArena* arena) | |
{ | |
SpriteBatch* batch = wArenaPush(arena, sizeof(SpriteBatch)); | |
batch->handles = wArenaPush(arena, sizeof(SpriteHandle) * cap); | |
batch->sprites = wArenaPush(arena, sizeof(Sprite) * cap); | |
batch->sprites2 = wArenaPush(arena, sizeof(Sprite) * cap); | |
batch->capacity = cap; | |
wInitBatch(&batch->batch, | |
game.texture, game.shader, | |
wRenderBatch_ArraysInstanced, wRenderBatch_TriangleStrip, | |
sizeof(Sprite), 4, | |
batch->sprites, NULL); | |
wConstructBatchGraphicsState(&batch->batch); | |
batch->scale = 1.0; | |
batch->tint = 0xFFFFFFFF; | |
batch->batch.blend = wRenderBatch_BlendPremultiplied; | |
return batch; | |
} | |
void drawSprites(SpriteBatch* batch) | |
{ | |
wRenderBatch* rb = &batch->batch; | |
rb->elementCount = batch->count; | |
batch->vw = game.state.width; | |
batch->vh = game.state.height; | |
batch->itw = 1.0f / rb->texture->w; | |
batch->ith = 1.0f / rb->texture->h; | |
wDrawBatch(&game.state, rb, batch); | |
batch->count = 0; | |
} | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment