From 9c2856eb872cc5b71d3a168d53b415c69968d316 Mon Sep 17 00:00:00 2001 From: Shariq Shah Date: Mon, 8 Jan 2018 20:32:28 +1100 Subject: [PATCH] Added primitive support to immediate renderer and put blender addon under version control --- README.md | 1 + assets/models/cube.symbres | Bin 0 -> 1312 bytes assets/models/sphere.symbres | Bin 0 -> 8656 bytes assets/shaders/im_geom.frag | 4 +- assets/shaders/im_geom.vert | 4 - assets/test_scene.symtres | 2 +- blender_addon/io_symmetry_exp/__init__.py | 34 + blender_addon/io_symmetry_exp/exporter.py | 95 +++ build/genie.lua | 14 +- src/libsymmetry/game.c | 60 +- src/libsymmetry/geometry.c | 774 +++++++++++----------- src/libsymmetry/im_render.c | 124 ++-- src/libsymmetry/im_render.h | 26 +- 13 files changed, 673 insertions(+), 465 deletions(-) create mode 100644 assets/models/cube.symbres create mode 100644 assets/models/sphere.symbres create mode 100644 blender_addon/io_symmetry_exp/__init__.py create mode 100644 blender_addon/io_symmetry_exp/exporter.py diff --git a/README.md b/README.md index 637679f..43960af 100644 --- a/README.md +++ b/README.md @@ -155,6 +155,7 @@ - ## TODO + - Convert IM_Vertex array to only be used as temporary storage for vertices between begin and end calls - Physics forces/torque etc - Replace all renderer_check_gl calls with GL_CHECK macro - Fix lights type not being correctly saved/loaded from file diff --git a/assets/models/cube.symbres b/assets/models/cube.symbres new file mode 100644 index 0000000000000000000000000000000000000000..805312fd21fe7e713aff58169a1e8e41887bdc0d GIT binary patch literal 1312 zcmc(eIZnh-5Jb&BfLT54J2;1wMe=pv7952OZ~zjV63paeq;LQt5?+JK6s?KD(o^@; zuV39in7Sy6+Mq4QU>qi35~g4pW}pYNFbDHc!U8P95-h_CtU?8SSc7%gfKAwfZPp4k!OP>@$9*$+e`umV>(%XbzigvFrI-GS=LY?`d}`dIK6Ll!uKT0+ zS?=*(nRy4-eU>tPhx{)2^Bbl6-Mq7Ve3tJlJc4n;5%?5tbm)~ zyYM~uKHLl|;Ro9=xZhJMbw$h( z>(&(Zlok}vT|XlGcd67ecm0Us-y55=J6e_(dK#OHy=~1+#AhYqFF9c=OWB@n+qkx{ zqpX=di6-gzv=_&pv8`Zz=XI`g$h8mN&L@|BI+y(nyXwS3c#B$`*M9!V@8Prgka6*- z`~28LZ#kxT)XMDz*SLXs;b+Luah>+&T;z^5XqnbCrPJOVZ++)={J%;IvN7w%7gk)n zf2Tdzvvn#SijT40o}2QX#ai0G*CFzvo3(MZf5%(jc^$u#{V;L&%#Q6`?ZLVHEVftn z#-m(amvfyy=CD<<51(R9T}$i-PTz`uuukRshT>hUy)|Q>L|u0??i#IQedl$&bGb(6 za$T_xV~_2|v+JtL)fIKc^RoXPoTXU9$63R(+4r&E&g8kc7WPcc&AOQzG3nV2)X8IV zedo1~bGb(QcU{iwx%W^<`CJ^-Y0r+omzX#gQ+tNxG08J)-nS0cVUOkGaR!~sI=%Fx z@)%+x9s)X(j~y~w@G9?Eme z{olRL9z55%JlEsyIi71j?m5;;dpP=b+W*n#trIb6ZJo>aKG#0W&g&jBu;=vmRr|4y zbJ>q|tnc&4`uFul_a*D6ywMx2>AB&dR&VsUb$lOdp87_;-r`(7`_>Pg)ZeV>dgIx} zdFLJ0Wt};jZYUhLc~{reS+k1|opyW6+NCq%+I8r>I}35YZPD=JmW!4YfPXRCi_2O^ zW)nB>YFXYovdH@&J9^Dch25;dZPSJ|-LiB>)=m7$r8)WE&#k4IO%InfGp>E_g6OZ- zci!q;Q}A{@x$M)q?B~V}qdO$^x|aC=(+J4Vf)+hh;nHF>tq z=E}2+tLKI$YZ7ai*}vD}y2>++82fj;^_|!8;dA3Lt%WDK+JkfXS)_H_ntSfA%eht_ z*i>L&71>vrYgyPki9LBhzRwo-v=uUH3@_GP($hA!vL7$D)!|(B96GU9dloEVuk`OR=XEZ}M~`D)*;a#UhCMWd#QV}z1g#SvOQbhd7aC>-9DYme*9cK zH_mnH$?mK6Z=Hxw{n;_@x7Kuxc#C&s79OqRx$c4PrJn2F$ezjlq<2TE#dF>+uJp3Jkz{Zzj@JeTL2|IH9rd+^+Pc|Gp_V-M~{?p^lazUN+N51#8> zp6hYn_Z;iE2gd$Lecn2;&r{!aF5mlH`z$-Jdx(3E^V*MfoXdW!WBrO|-j{p^ z-IuH%nyEKh({sZ^t={Ny>-gShzg}-~E}wnt`|MlO_4@2vC(c)ya@VW$zVzO&@moZs zIq90_rtj(M*c9Wji1R0XPxI3?#iZ})8somN6_>^w8*}_g8nwo&=cSl5XK!@|8(%N) z-i+7sRBJ5Nl734bYmM(s-ZZ~jFMUtf>Nsns7>^Cc&wtZ?IvwYB{(9rpxzhJ^t*4QE zI4 Export > Export to Symmetry", + "category": "Import-Export" +} + +# Ensure that we reload our dependencies if we ourselves are reloaded by Blender +if "bpy" in locals(): + import imp; + if "exporter" in locals(): + imp.reload(exporter); + +import bpy +from . import exporter + + +def menu_func(self, context): + self.layout.operator(ExportSymmetry.bl_idname, text="Symbres (.symbres)"); + +def register(): + bpy.utils.register_module(__name__); + bpy.types.INFO_MT_file_export.append(menu_func); + +def unregister(): + bpy.utils.unregister_module(__name__); + bpy.types.INFO_MT_file_export.remove(menu_func); + + +if __name__ == "__main__": + register() diff --git a/blender_addon/io_symmetry_exp/exporter.py b/blender_addon/io_symmetry_exp/exporter.py new file mode 100644 index 0000000..6c99623 --- /dev/null +++ b/blender_addon/io_symmetry_exp/exporter.py @@ -0,0 +1,95 @@ +import bpy +import bmesh +import struct +from math import radians +from bpy_extras.io_utils import ExportHelper + +class ExportSymmetry(bpy.types.Operator, ExportHelper): + bl_idname = "export_symmetry.symbres"; + bl_label = "Symmetry Exporter"; + bl_options = {'PRESET'}; + filename_ext = ".symbres"; + + def execute(self, context): + scene = context.scene + activeObject = scene.objects.active + + if not activeObject or str(activeObject.type) != 'MESH': + raise NameError("Cannot export : Object %s is not a mesh" % activeObject) + + print("Exporting : " + activeObject.name) + + # Rotate -90 deg on x axis to compensate for blender's different orientation + activeObject.rotation_euler[0] = radians(-90) + bpy.ops.object.transform_apply(location = True, scale = True, rotation = True) + + mesh = activeObject.to_mesh(scene, True, 'PREVIEW') + bm = bmesh.new() + bm.from_mesh(mesh) + bmesh.ops.triangulate(bm, faces = bm.faces) + + indices = [] + vertices = [] + normals = [] + uvs = [] + + if len(mesh.uv_layers) > 0: + uv_layer = bm.loops.layers.uv.values()[0] + index = 0; + for face in bm.faces: + for loop in face.loops: + uv = loop[uv_layer].uv + uv.y = 1.0 - uv.y + vert = loop.vert + vertices.append(vert.co.to_tuple()) + normals.append(vert.normal.to_tuple()) + uvs.append(uv.to_tuple()) + indices.append(index) + index += 1 + else: + raise NameError("No uv layers detected. Did you forget to unwrap?") + + bm.free() + del bm + + # Reset object's previous rotation + activeObject.rotation_euler[0] = radians(90) + bpy.ops.object.transform_apply(location = True, scale = True, rotation = True) + + file = open(self.filepath, 'bw') + + # Header + file.write(struct.pack('i', len(indices))) + file.write(struct.pack('i', len(vertices))) + file.write(struct.pack('i', len(normals))) + file.write(struct.pack('i', len(uvs))) + + print ("Num Indices : %d" % len(indices)) + print ("Indices : \n %s \n\n" % str(indices)) + + print ("Num Vertices : %d" % len(vertices)) + print ("Vertices : \n %s \n\n" % str(vertices)) + + print ("Num Normals : %d" % len(normals)) + print ("Normals : \n %s \n\n" % str(normals)) + + print ("Num UVs : %d" % len(uvs)) + print ("UVs : \n %s \n\n" % str(uvs)) + + # Body + for index in indices: + file.write(struct.pack('i', index)) + + for vertex in vertices: + file.write(struct.pack('fff', vertex[0], vertex[1], vertex[2])) + + for normal in normals: + file.write(struct.pack('fff', normal[0], normal[1], normal[2])) + + for uv in uvs: + file.write(struct.pack('ff', uv[0], uv[1])) + + file.close() + + print("Done!") + return {'FINISHED'}; diff --git a/build/genie.lua b/build/genie.lua index daf24da..bdf2488 100644 --- a/build/genie.lua +++ b/build/genie.lua @@ -19,7 +19,7 @@ solution "Symmetry" end configuration "Debug" - if (_ACTION ~= nil and _ACTION ~= "postbuild_copy") then + if (_ACTION ~= nil and _ACTION ~= "postbuild_copy" and _ACTION ~= "build_addon") then os.mkdir(_ACTION .. "/debug") targetdir (_ACTION .. "/debug") end @@ -27,7 +27,7 @@ solution "Symmetry" flags { "Symbols" } configuration "Release" - if (_ACTION ~= nil and _ACTION ~= "postbuild_copy") then + if (_ACTION ~= nil and _ACTION ~= "postbuild_copy" and _ACTION ~= "build_addon") then os.mkdir(_ACTION .. "/release") targetdir (_ACTION .. "/release") end @@ -133,3 +133,13 @@ solution "Symmetry" configuration "Debug" defines {"GL_DEBUG_CONTEXT"} + + + newaction { + trigger = "build_addon", + description = "Build blender addon into zip file that can be loaded into blender", + execute = function () + local output = os.outputof("cd ../blender_addon && zip -r io_symmetry_exp.zip io_symmetry_exp/__init__.py io_symmetry_exp/exporter.py && mv io_symmetry_exp.zip ../build"); + printf("Output of blender addon build : \n%s\n", output) + end + } \ No newline at end of file diff --git a/src/libsymmetry/game.c b/src/libsymmetry/game.c index 20d098a..eafef5b 100644 --- a/src/libsymmetry/game.c +++ b/src/libsymmetry/game.c @@ -456,55 +456,59 @@ void debug(float dt) vec3 im_position = { 0.f, 20.f, 0.f }; vec3 im_scale = { 1.f, 1.f, 1.f }; quat im_rot = { 0.f, 0.f, 0.f, 1.f }; + vec4 im_color = { 0.f, 1.f, 1.f, 1.f }; quat_identity(&im_rot); - im_begin(im_position, im_rot, im_scale, GL_LINES); + im_begin(im_position, im_rot, im_scale, im_color, GL_LINES); - im_color(0.f, 1.f, 0.f, 1.f); im_pos(0.f, 0.f, 0.f); im_pos(100.f, 100.f, 10.f); im_end(); im_position.x = -10; - im_begin(im_position, im_rot, im_scale, GL_TRIANGLES); + + im_color.x = 1.f; + im_color.y = 0.f; + im_begin(im_position, im_rot, im_scale, im_color, GL_TRIANGLES); + + float length = 200 * sin(dt); //Front im_pos(0.f, 0.f, 0.f); - im_pos(0.f, 20.f, 0.f); - im_pos(20.f, 20.f, 0.f); - im_pos(20.f, 20.f, 0.f); - im_pos(20.f, 0.f, 0.f); + im_pos(0.f, length, 0.f); + im_pos(length, length, 0.f); + im_pos(length, length, 0.f); + im_pos(length, 0.f, 0.f); im_pos( 0.f, 0.f, 0.f); //Back - im_pos(0.f, 0.f, 20.f); - im_pos(0.f, 20.f, 20.f); - im_pos(20.f, 20.f, 20.f); - im_pos(20.f, 20.f, 20.f); - im_pos(20.f, 0.f, 20.f); - im_pos( 0.f, 0.f, 20.f); + im_pos(0.f, 0.f, length); + im_pos(0.f, length, length); + im_pos(length, length, length); + im_pos(length, length, length); + im_pos(length, 0.f, length); + im_pos( 0.f, 0.f, length); //Left im_pos(0.f, 0.f, 0.f); - im_pos(0.f, 0.f, 20.f); - im_pos(0.f, 20.f, 20.f); - im_pos(0.f, 20.f, 20.f); - im_pos(0.f, 20.f, 0.f); - im_pos(0.f, 0.f, 20.f); + im_pos(0.f, 0.f, length); + im_pos(0.f, length, length); + im_pos(0.f, length, length); + im_pos(0.f, length, 0.f); + im_pos(0.f, 0.f, length); //Right - im_pos(20.f, 0.f, 0.f); - im_pos(20.f, 0.f, 20.f); - im_pos(20.f, 20.f, 20.f); - im_pos(20.f, 20.f, 20.f); - im_pos(20.f, 20.f, 0.f); - im_pos(20.f, 0.f, 20.f); + im_pos(length, 0.f, 0.f); + im_pos(length, 0.f, length); + im_pos(length, length, length); + im_pos(length, length, length); + im_pos(length, length, 0.f); + im_pos(length, 0.f, length); im_end(); im_position.x = -30.f; - im_begin(im_position, im_rot, im_scale, GL_LINES); - im_color(1.f, 1.f, 0.f, 1.f); + im_begin(im_position, im_rot, im_scale, im_color, GL_LINES); im_pos(0.f, 0.f, 0.f); im_pos(0.f, 0.f, 10.f); @@ -520,7 +524,9 @@ void debug(float dt) im_end(); - + vec4 prim_color = {1.f, 1.f, 0.f, 1.f}; + im_cube(5.f, im_position, im_rot, prim_color, GDM_TRIANGLES); + im_sphere(2.f, im_position, im_rot, prim_color, GDM_TRIANGLES); } bool run(void) diff --git a/src/libsymmetry/geometry.c b/src/libsymmetry/geometry.c index b5887bb..d126fd9 100644 --- a/src/libsymmetry/geometry.c +++ b/src/libsymmetry/geometry.c @@ -1,391 +1,391 @@ -#include "geometry.h" -#include "../common/array.h" -#include "../common/string_utils.h" -#include "../common/log.h" -#include "renderer.h" -#include "transform.h" -#include "../common/common.h" -#include "gl_load.h" - -#include -#include -#include -#include -#include -#include - -/* Data */ -static struct Geometry* geometry_list; -static int* empty_indices; -static GLenum* draw_modes; - -static int load_from_file(struct Geometry* geometry, const char* filename); -static void create_vao(struct Geometry* geometry); -static struct Geometry* generate_new_index(int* out_new_index); - -void geom_init(void) -{ - geometry_list = array_new(struct Geometry); - empty_indices = array_new(int); - draw_modes = array_new_cap(GLenum, GDM_NUM_DRAWMODES); - draw_modes[GDM_TRIANGLES] = GL_TRIANGLES; - draw_modes[GDM_LINES] = GL_LINES; - draw_modes[GDM_POINTS] = GL_POINTS; -} - -int geom_find(const char* filename) -{ - int index = -1; - for(int i = 0; i < array_len(geometry_list); i++) - { - struct Geometry* geometry = &geometry_list[i]; - if(strcmp(geometry->filename, filename) == 0) - { - index = i; - break; - } - } - return index; -} - -void geom_bounding_volume_generate(int index) -{ - struct Geometry* geometry = &geometry_list[index]; - struct Bounding_Box* box = &geometry->bounding_box; - struct Bounding_Sphere* sphere = &geometry->bounding_sphere; - - vec3_fill(&box->max, -FLT_MIN, -FLT_MIN, -FLT_MIN); - vec3_fill(&box->min, FLT_MAX, FLT_MAX, FLT_MAX); - vec3_fill(&sphere->center, 0.f, 0.f, 0.f); - sphere->radius = 0.f; - - for(int i = 0; i < array_len(geometry->vertices); i++) - { - vec3* vertex = &geometry->vertices[i]; - if(vertex->x > box->max.x) box->max.x = vertex->x; - if(vertex->y > box->max.y) box->max.y = vertex->y; - if(vertex->z > box->max.z) box->max.z = vertex->z; - - if(vertex->x < box->min.x) box->min.x = vertex->x; - if(vertex->y < box->min.y) box->min.y = vertex->y; - if(vertex->z < box->min.z) box->min.z = vertex->z; - } - vec3_add(&sphere->center, &box->max, &box->min); - vec3_scale(&sphere->center, &sphere->center, 0.5f); - vec3 len_vec; - vec3_sub(&len_vec, &box->max, &sphere->center); - sphere->radius = fabsf(vec3_len(&len_vec)); -} - -void geom_bounding_volume_generate_all(void) -{ - for(int i = 0; i < array_len(geometry_list); i++) - geom_bounding_volume_generate(i); -} - -static struct Geometry* generate_new_index(int* out_new_index) -{ - assert(out_new_index); - int empty_len = array_len(empty_indices); - struct Geometry* new_geo = NULL; - if(empty_len > 0) - { - *out_new_index = empty_indices[empty_len - 1]; - array_pop(empty_indices); - new_geo = &geometry_list[*out_new_index]; - } - else - { - new_geo = array_grow(geometry_list, struct Geometry); - *out_new_index = array_len(geometry_list) - 1; - } - return new_geo; -} - -int geom_create_from_file(const char* name) -{ - assert(name); - // check if exists - int index = geom_find(name); - if(index == -1) - { - /* add new geometry object or overwrite existing one */ - struct Geometry* new_geo = NULL; - new_geo = generate_new_index(&index); - assert(new_geo); - - if(load_from_file(new_geo, name)) - { - create_vao(new_geo); - geom_bounding_volume_generate(index); - } - else - { - /* TODO: Some error here, find it and fix it */ - array_pop(geometry_list); - index = -1; - } - } - else - { - geometry_list[index].ref_count++; - } - return index; -} - -int geom_create(const char* name, - vec3* vertices, - vec2* uvs, - vec3* normals, - uint* indices, - vec3* vertex_colors) -{ - assert(name && vertices && uvs && normals && indices); - int index = -1; - /* add new geometry object or overwrite existing one */ - struct Geometry* new_geo = NULL; - new_geo = generate_new_index(&index); - assert(new_geo); - new_geo->filename = str_new(name); - new_geo->vertices = array_new_cap(vec3, array_len(vertices)); - array_copy(vertices, new_geo->vertices); - new_geo->normals = array_new_cap(vec3, array_len(normals)); - array_copy(normals, new_geo->normals); - new_geo->uvs = array_new_cap(vec2, array_len(uvs)); - array_copy(uvs, new_geo->uvs); - new_geo->indices = array_new_cap(uint, array_len(indices)); - array_copy(indices, new_geo->indices); - if(vertex_colors) - { - new_geo->vertex_colors = array_new_cap(vec3, array_len(vertex_colors)); - array_copy(vertex_colors, new_geo->vertex_colors); - } - else - { - new_geo->vertex_colors = array_new(vec3); - } - create_vao(new_geo); - //generateBoundingBox(index); - return index; -} - - -void geom_remove(int index) -{ - if(index >= 0 && index < array_len(geometry_list)) - { - struct Geometry* geometry = &geometry_list[index]; - if(geometry->ref_count >= 0) - { - geometry->ref_count--; - if(geometry->ref_count < 0) - { - if(geometry->indices) array_free(geometry->indices); - if(geometry->vertices) array_free(geometry->vertices); - if(geometry->uvs) array_free(geometry->uvs); - if(geometry->normals) array_free(geometry->normals); - if(geometry->vertex_colors) array_free(geometry->vertex_colors); - if(geometry->filename) free(geometry->filename); - geometry->indices = NULL; - geometry->vertices = NULL; - geometry->uvs = NULL; - geometry->normals = NULL; - geometry->vertex_colors = NULL; - geometry->filename = NULL; - - glDeleteBuffers(1, &geometry->vertex_vbo); - glDeleteBuffers(1, &geometry->color_vbo); - glDeleteBuffers(1, &geometry->uv_vbo); - glDeleteBuffers(1, &geometry->normal_vbo); - glDeleteBuffers(1, &geometry->index_vbo); - glDeleteVertexArrays(1, &geometry->vao); - +#include "geometry.h" +#include "../common/array.h" +#include "../common/string_utils.h" +#include "../common/log.h" +#include "renderer.h" +#include "transform.h" +#include "../common/common.h" +#include "gl_load.h" + +#include +#include +#include +#include +#include +#include + +/* Data */ +static struct Geometry* geometry_list; +static int* empty_indices; +static GLenum* draw_modes; + +static int load_from_file(struct Geometry* geometry, const char* filename); +static void create_vao(struct Geometry* geometry); +static struct Geometry* generate_new_index(int* out_new_index); + +void geom_init(void) +{ + geometry_list = array_new(struct Geometry); + empty_indices = array_new(int); + draw_modes = array_new_cap(GLenum, GDM_NUM_DRAWMODES); + draw_modes[GDM_TRIANGLES] = GL_TRIANGLES; + draw_modes[GDM_LINES] = GL_LINES; + draw_modes[GDM_POINTS] = GL_POINTS; +} + +int geom_find(const char* filename) +{ + int index = -1; + for(int i = 0; i < array_len(geometry_list); i++) + { + struct Geometry* geometry = &geometry_list[i]; + if(strcmp(geometry->filename, filename) == 0) + { + index = i; + break; + } + } + return index; +} + +void geom_bounding_volume_generate(int index) +{ + struct Geometry* geometry = &geometry_list[index]; + struct Bounding_Box* box = &geometry->bounding_box; + struct Bounding_Sphere* sphere = &geometry->bounding_sphere; + + vec3_fill(&box->max, -FLT_MIN, -FLT_MIN, -FLT_MIN); + vec3_fill(&box->min, FLT_MAX, FLT_MAX, FLT_MAX); + vec3_fill(&sphere->center, 0.f, 0.f, 0.f); + sphere->radius = 0.f; + + for(int i = 0; i < array_len(geometry->vertices); i++) + { + vec3* vertex = &geometry->vertices[i]; + if(vertex->x > box->max.x) box->max.x = vertex->x; + if(vertex->y > box->max.y) box->max.y = vertex->y; + if(vertex->z > box->max.z) box->max.z = vertex->z; + + if(vertex->x < box->min.x) box->min.x = vertex->x; + if(vertex->y < box->min.y) box->min.y = vertex->y; + if(vertex->z < box->min.z) box->min.z = vertex->z; + } + vec3_add(&sphere->center, &box->max, &box->min); + vec3_scale(&sphere->center, &sphere->center, 0.5f); + vec3 len_vec; + vec3_sub(&len_vec, &box->max, &sphere->center); + sphere->radius = fabsf(vec3_len(&len_vec)); +} + +void geom_bounding_volume_generate_all(void) +{ + for(int i = 0; i < array_len(geometry_list); i++) + geom_bounding_volume_generate(i); +} + +static struct Geometry* generate_new_index(int* out_new_index) +{ + assert(out_new_index); + int empty_len = array_len(empty_indices); + struct Geometry* new_geo = NULL; + if(empty_len > 0) + { + *out_new_index = empty_indices[empty_len - 1]; + array_pop(empty_indices); + new_geo = &geometry_list[*out_new_index]; + } + else + { + new_geo = array_grow(geometry_list, struct Geometry); + *out_new_index = array_len(geometry_list) - 1; + } + return new_geo; +} + +int geom_create_from_file(const char* name) +{ + assert(name); + // check if exists + int index = geom_find(name); + if(index == -1) + { + /* add new geometry object or overwrite existing one */ + struct Geometry* new_geo = NULL; + new_geo = generate_new_index(&index); + assert(new_geo); + + if(load_from_file(new_geo, name)) + { + create_vao(new_geo); + geom_bounding_volume_generate(index); + } + else + { + /* TODO: Some error here, find it and fix it */ + array_pop(geometry_list); + index = -1; + } + } + else + { + geometry_list[index].ref_count++; + } + return index; +} + +int geom_create(const char* name, + vec3* vertices, + vec2* uvs, + vec3* normals, + uint* indices, + vec3* vertex_colors) +{ + assert(name && vertices && uvs && normals && indices); + int index = -1; + /* add new geometry object or overwrite existing one */ + struct Geometry* new_geo = NULL; + new_geo = generate_new_index(&index); + assert(new_geo); + new_geo->filename = str_new(name); + new_geo->vertices = array_new_cap(vec3, array_len(vertices)); + array_copy(vertices, new_geo->vertices); + new_geo->normals = array_new_cap(vec3, array_len(normals)); + array_copy(normals, new_geo->normals); + new_geo->uvs = array_new_cap(vec2, array_len(uvs)); + array_copy(uvs, new_geo->uvs); + new_geo->indices = array_new_cap(uint, array_len(indices)); + array_copy(indices, new_geo->indices); + if(vertex_colors) + { + new_geo->vertex_colors = array_new_cap(vec3, array_len(vertex_colors)); + array_copy(vertex_colors, new_geo->vertex_colors); + } + else + { + new_geo->vertex_colors = array_new(vec3); + } + create_vao(new_geo); + //generateBoundingBox(index); + return index; +} + + +void geom_remove(int index) +{ + if(index >= 0 && index < array_len(geometry_list)) + { + struct Geometry* geometry = &geometry_list[index]; + if(geometry->ref_count >= 0) + { + geometry->ref_count--; + if(geometry->ref_count < 0) + { + if(geometry->indices) array_free(geometry->indices); + if(geometry->vertices) array_free(geometry->vertices); + if(geometry->uvs) array_free(geometry->uvs); + if(geometry->normals) array_free(geometry->normals); + if(geometry->vertex_colors) array_free(geometry->vertex_colors); + if(geometry->filename) free(geometry->filename); + geometry->indices = NULL; + geometry->vertices = NULL; + geometry->uvs = NULL; + geometry->normals = NULL; + geometry->vertex_colors = NULL; + geometry->filename = NULL; + + glDeleteBuffers(1, &geometry->vertex_vbo); + glDeleteBuffers(1, &geometry->color_vbo); + glDeleteBuffers(1, &geometry->uv_vbo); + glDeleteBuffers(1, &geometry->normal_vbo); + glDeleteBuffers(1, &geometry->index_vbo); + glDeleteVertexArrays(1, &geometry->vao); + geometry->vertex_vbo = 0; geometry->color_vbo = 0; geometry->uv_vbo = 0; geometry->normal_vbo = 0; - geometry->index_vbo = 0; - geometry->vao = 0; - - array_push(empty_indices, index, int); - } - } - } -} - -void geom_cleanup(void) -{ - for(int i = 0; i < array_len(geometry_list); i++) - geom_remove(i); - - array_free(geometry_list); - array_free(empty_indices); - array_free(draw_modes); -} - -static int load_from_file(struct Geometry* geometry, const char* filename) -{ - assert(filename); - int success = 1; - char* full_path = str_new("models/%s", filename); - - FILE* file = platform->file.open(DIRT_INSTALL, full_path, "rb"); - free(full_path); - if(file) - { - const uint32 INDEX_SIZE = sizeof(uint32); - const uint32 VEC3_SIZE = sizeof(vec3); - const uint32 VEC2_SIZE = sizeof(vec2); - uint32 header[4]; - size_t bytes_read = 0; - if((bytes_read = fread(header, INDEX_SIZE, 4, file)) <= 0) - { - log_error("geometry:load_from_file", "Read failed"); - success = 0; - } - else - { - uint32 indices_count = header[0]; - uint32 vertices_count = header[1]; - uint32 normals_count = header[2]; - uint32 uvs_count = header[3]; - // Indices - geometry->indices = array_new_cap(uint, indices_count); - fread(geometry->indices, INDEX_SIZE, indices_count, file); - array_match_len_cap(geometry->indices); - // Vertices - geometry->vertices = array_new_cap(vec3, vertices_count); - fread(geometry->vertices, VEC3_SIZE, vertices_count, file); - array_match_len_cap(geometry->vertices); - // Normals - geometry->normals = array_new_cap(vec3, normals_count); - fread(geometry->normals, VEC3_SIZE, normals_count, file); - array_match_len_cap(geometry->normals); - // Uvs - geometry->uvs = array_new_cap(vec2, uvs_count); - fread(geometry->uvs, VEC2_SIZE, uvs_count, file); - array_match_len_cap(geometry->uvs); - - geometry->vertex_colors = array_new(vec3); - } - fclose(file); - geometry->filename = str_new(filename); - geometry->draw_indexed = 1; - geometry->ref_count++; - } - else - { - success = 0; - } - return success; -} - -static void create_vao(struct Geometry* geometry) -{ - // TODO: Add support for different model formats and interleaving VBO - assert(geometry); - glGenVertexArrays(1, &geometry->vao); - glBindVertexArray(geometry->vao); - - glGenBuffers(1, &geometry->vertex_vbo); - glBindBuffer(GL_ARRAY_BUFFER, geometry->vertex_vbo); - glBufferData(GL_ARRAY_BUFFER, - array_len(geometry->vertices) * sizeof(vec3), - geometry->vertices, - GL_STATIC_DRAW); - renderer_check_glerror("geometry:create_vbo:vertex"); - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); - - if(array_len(geometry->normals) > 0) - { - glGenBuffers(1, &geometry->normal_vbo); - glBindBuffer(GL_ARRAY_BUFFER, geometry->normal_vbo); - glBufferData(GL_ARRAY_BUFFER, - array_len(geometry->normals) * sizeof(vec3), - geometry->normals, - GL_STATIC_DRAW); - renderer_check_glerror("geometry:create_vbo:normal"); - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 3, GL_FLOAT, GL_TRUE, 0, 0); - } - - if(array_len(geometry->uvs) > 0) - { - glGenBuffers(1, &geometry->uv_vbo); - glBindBuffer(GL_ARRAY_BUFFER, geometry->uv_vbo); - glBufferData(GL_ARRAY_BUFFER, - array_len(geometry->uvs) * sizeof(vec2), - geometry->uvs, - GL_STATIC_DRAW); - renderer_check_glerror("geometry:create_vbo:uv"); - glEnableVertexAttribArray(2); - glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, 0); - } - - if(array_len(geometry->vertex_colors) > 0) - { - glGenBuffers(1, &geometry->color_vbo); - glBindBuffer(GL_ARRAY_BUFFER, geometry->color_vbo); - glBufferData(GL_ARRAY_BUFFER, - array_len(geometry->vertex_colors) * sizeof(vec3), - geometry->vertex_colors, - GL_STATIC_DRAW); - renderer_check_glerror("geometry:create_vbo:color"); - glEnableVertexAttribArray(3); - glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 0, 0); - } - - if(array_len(geometry->indices) > 0) - { - glGenBuffers(1, &geometry->index_vbo); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, geometry->index_vbo); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, - array_len(geometry->indices) * sizeof(GLuint), - geometry->indices, - GL_STATIC_DRAW); - geometry->draw_indexed = 1; - } - glBindVertexArray(0); -} - -void geom_render(int index, enum Geometry_Draw_Mode draw_mode) -{ - assert((int)draw_mode > -1 && draw_mode < GDM_NUM_DRAWMODES); - struct Geometry* geo = &geometry_list[index]; - glBindVertexArray(geo->vao); - if(geo->draw_indexed) - glDrawElements(draw_modes[draw_mode], array_len(geo->indices), GL_UNSIGNED_INT, (void*)0); - else - glDrawArrays(draw_modes[draw_mode], 0, array_len(geo->vertices)); - glBindVertexArray(0); - -} - -int geom_render_in_frustum(int index, - vec4* frustum, - struct Entity* entity, - enum Geometry_Draw_Mode draw_mode) -{ - struct Geometry* geometry = &geometry_list[index]; - int indices_rendered = 0; - int intersection = bv_intersect_frustum_sphere(frustum, &geometry->bounding_sphere, entity); - if(intersection == IT_INTERSECT || intersection == IT_INSIDE) - { - geom_render(index, draw_mode); - indices_rendered = array_len(geometry->indices); - /* intersection = bv_intersect_frustum_box(frustum, &geometry->bounding_box, entity); */ - /* if(intersection == IT_INTERSECT || intersection == IT_INSIDE) */ - /* { */ - /* geom_render(index, draw_mode); */ - /* rendered = array_len(geometry->indices); */ - /* } */ - } - return indices_rendered; -} - -struct Geometry* geom_get(int index) -{ - assert(index > -1 && index < array_len(geometry_list)); - return &geometry_list[index]; -} + geometry->index_vbo = 0; + geometry->vao = 0; + + array_push(empty_indices, index, int); + } + } + } +} + +void geom_cleanup(void) +{ + for(int i = 0; i < array_len(geometry_list); i++) + geom_remove(i); + + array_free(geometry_list); + array_free(empty_indices); + array_free(draw_modes); +} + +static int load_from_file(struct Geometry* geometry, const char* filename) +{ + assert(filename); + int success = 1; + char* full_path = str_new("models/%s", filename); + + FILE* file = platform->file.open(DIRT_INSTALL, full_path, "rb"); + free(full_path); + if(file) + { + const uint32 INDEX_SIZE = sizeof(uint32); + const uint32 VEC3_SIZE = sizeof(vec3); + const uint32 VEC2_SIZE = sizeof(vec2); + uint32 header[4]; + size_t bytes_read = 0; + if((bytes_read = fread(header, INDEX_SIZE, 4, file)) <= 0) + { + log_error("geometry:load_from_file", "Read failed"); + success = 0; + } + else + { + uint32 indices_count = header[0]; + uint32 vertices_count = header[1]; + uint32 normals_count = header[2]; + uint32 uvs_count = header[3]; + // Indices + geometry->indices = array_new_cap(uint, indices_count); + fread(geometry->indices, INDEX_SIZE, indices_count, file); + array_match_len_cap(geometry->indices); + // Vertices + geometry->vertices = array_new_cap(vec3, vertices_count); + fread(geometry->vertices, VEC3_SIZE, vertices_count, file); + array_match_len_cap(geometry->vertices); + // Normals + geometry->normals = array_new_cap(vec3, normals_count); + fread(geometry->normals, VEC3_SIZE, normals_count, file); + array_match_len_cap(geometry->normals); + // Uvs + geometry->uvs = array_new_cap(vec2, uvs_count); + fread(geometry->uvs, VEC2_SIZE, uvs_count, file); + array_match_len_cap(geometry->uvs); + + geometry->vertex_colors = array_new(vec3); + } + fclose(file); + geometry->filename = str_new(filename); + geometry->draw_indexed = 1; + geometry->ref_count++; + } + else + { + success = 0; + } + return success; +} + +static void create_vao(struct Geometry* geometry) +{ + // TODO: Add support for different model formats and interleaving VBO + assert(geometry); + glGenVertexArrays(1, &geometry->vao); + glBindVertexArray(geometry->vao); + + glGenBuffers(1, &geometry->vertex_vbo); + glBindBuffer(GL_ARRAY_BUFFER, geometry->vertex_vbo); + glBufferData(GL_ARRAY_BUFFER, + array_len(geometry->vertices) * sizeof(vec3), + geometry->vertices, + GL_STATIC_DRAW); + renderer_check_glerror("geometry:create_vbo:vertex"); + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); + + if(array_len(geometry->normals) > 0) + { + glGenBuffers(1, &geometry->normal_vbo); + glBindBuffer(GL_ARRAY_BUFFER, geometry->normal_vbo); + glBufferData(GL_ARRAY_BUFFER, + array_len(geometry->normals) * sizeof(vec3), + geometry->normals, + GL_STATIC_DRAW); + renderer_check_glerror("geometry:create_vbo:normal"); + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_TRUE, 0, 0); + } + + if(array_len(geometry->uvs) > 0) + { + glGenBuffers(1, &geometry->uv_vbo); + glBindBuffer(GL_ARRAY_BUFFER, geometry->uv_vbo); + glBufferData(GL_ARRAY_BUFFER, + array_len(geometry->uvs) * sizeof(vec2), + geometry->uvs, + GL_STATIC_DRAW); + renderer_check_glerror("geometry:create_vbo:uv"); + glEnableVertexAttribArray(2); + glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, 0); + } + + if(array_len(geometry->vertex_colors) > 0) + { + glGenBuffers(1, &geometry->color_vbo); + glBindBuffer(GL_ARRAY_BUFFER, geometry->color_vbo); + glBufferData(GL_ARRAY_BUFFER, + array_len(geometry->vertex_colors) * sizeof(vec3), + geometry->vertex_colors, + GL_STATIC_DRAW); + renderer_check_glerror("geometry:create_vbo:color"); + glEnableVertexAttribArray(3); + glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 0, 0); + } + + if(array_len(geometry->indices) > 0) + { + glGenBuffers(1, &geometry->index_vbo); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, geometry->index_vbo); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, + array_len(geometry->indices) * sizeof(GLuint), + geometry->indices, + GL_STATIC_DRAW); + geometry->draw_indexed = 1; + } + glBindVertexArray(0); +} + +void geom_render(int index, enum Geometry_Draw_Mode draw_mode) +{ + assert((int)draw_mode > -1 && draw_mode < GDM_NUM_DRAWMODES && index >= 0); + struct Geometry* geo = &geometry_list[index]; + glBindVertexArray(geo->vao); + if(geo->draw_indexed) + glDrawElements(draw_modes[draw_mode], array_len(geo->indices), GL_UNSIGNED_INT, (void*)0); + else + glDrawArrays(draw_modes[draw_mode], 0, array_len(geo->vertices)); + glBindVertexArray(0); + +} + +int geom_render_in_frustum(int index, + vec4* frustum, + struct Entity* entity, + enum Geometry_Draw_Mode draw_mode) +{ + struct Geometry* geometry = &geometry_list[index]; + int indices_rendered = 0; + int intersection = bv_intersect_frustum_sphere(frustum, &geometry->bounding_sphere, entity); + if(intersection == IT_INTERSECT || intersection == IT_INSIDE) + { + geom_render(index, draw_mode); + indices_rendered = array_len(geometry->indices); + /* intersection = bv_intersect_frustum_box(frustum, &geometry->bounding_box, entity); */ + /* if(intersection == IT_INTERSECT || intersection == IT_INSIDE) */ + /* { */ + /* geom_render(index, draw_mode); */ + /* rendered = array_len(geometry->indices); */ + /* } */ + } + return indices_rendered; +} + +struct Geometry* geom_get(int index) +{ + assert(index > -1 && index < array_len(geometry_list)); + return &geometry_list[index]; +} diff --git a/src/libsymmetry/im_render.c b/src/libsymmetry/im_render.c index a82ffca..f1bdcdc 100644 --- a/src/libsymmetry/im_render.c +++ b/src/libsymmetry/im_render.c @@ -6,8 +6,9 @@ #include "../common/num_types.h" #include "shader.h" #include "../common/log.h" +#include "geometry.h" -#define MAX_IM_VERTICES 4096 +#define MAX_IM_VERTICES 2048 #define MAX_IM_GEOMETRIES (MAX_IM_VERTICES / 2) static struct @@ -19,12 +20,11 @@ static struct int im_shader; int curr_geom; int curr_vertex; - vec4 default_color; } IM_State; static struct IM_Geom* active_geom = NULL; -static vec4 active_vertex_color = { 0.f, 0.f, 0.f, 0.f }; +static int active_vertex_index = 0; void im_init(void) { @@ -33,15 +33,15 @@ void im_init(void) glGenBuffers(1, &IM_State.vbo); glBindBuffer(GL_ARRAY_BUFFER, IM_State.vbo); - GL_CHECK(glBufferData(GL_ARRAY_BUFFER, sizeof(struct IM_Vertex) * MAX_IM_VERTICES, NULL, GL_STREAM_DRAW)); + GL_CHECK(glBufferData(GL_ARRAY_BUFFER, sizeof(struct IM_Vertex) * MAX_IM_VERTICES * MAX_IM_GEOMETRIES, NULL, GL_STREAM_DRAW)); //Position GL_CHECK(glVertexAttribPointer(ATTRIB_LOC_POSITION, 3, GL_FLOAT, GL_FALSE, sizeof(struct IM_Vertex), 0)); GL_CHECK(glEnableVertexAttribArray(ATTRIB_LOC_POSITION)); - //Color - GL_CHECK(glVertexAttribPointer(ATTRIB_LOC_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(struct IM_Vertex), sizeof(vec3))); - GL_CHECK(glEnableVertexAttribArray(ATTRIB_LOC_COLOR)); + ////Color + //GL_CHECK(glVertexAttribPointer(ATTRIB_LOC_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(struct IM_Vertex), sizeof(vec3))); + //GL_CHECK(glEnableVertexAttribArray(ATTRIB_LOC_COLOR)); glBindBuffer(GL_ARRAY_BUFFER, 0); @@ -51,8 +51,6 @@ void im_init(void) memset(&IM_State.vertices[0], 0, sizeof(struct IM_Vertex) * MAX_IM_VERTICES); IM_State.curr_geom = -1; IM_State.curr_vertex = 0; - vec4_fill(&IM_State.default_color, 1.f, 0.f, 1.f, 1.f); - vec4_assign(&active_vertex_color, &IM_State.default_color); IM_State.im_shader = shader_create("im_geom.vert", "im_geom.frag"); } @@ -72,7 +70,7 @@ void im_cleanup(void) IM_State.im_shader = -1; } -void im_begin(vec3 position, quat rotation, vec3 scale, int draw_mode) +void im_begin(vec3 position, quat rotation, vec3 scale, vec4 color, int draw_mode) { if(active_geom) { @@ -82,36 +80,79 @@ void im_begin(vec3 position, quat rotation, vec3 scale, int draw_mode) IM_State.curr_geom++; active_geom = &IM_State.geometries[IM_State.curr_geom]; active_geom->start_index = IM_State.curr_vertex; + active_geom->type = IGT_DYNAMIC; active_geom->draw_mode = draw_mode; vec3_assign(&active_geom->position, &position); vec3_assign(&active_geom->scale, &scale); + vec4_assign(&active_geom->color, &color); quat_assign(&active_geom->rotation, &rotation); } void im_pos(float x, float y, float z) { - vec3_fill(&IM_State.vertices[IM_State.curr_vertex].position, x, y, z); - vec4_assign(&IM_State.vertices[IM_State.curr_vertex].color, &active_vertex_color); + if(IM_State.curr_vertex == MAX_IM_VERTICES) + { + log_error("im_pos", "Buffer full!"); + return; + } + vec3_fill(&IM_State.vertices[active_vertex_index].position, x, y, z); IM_State.curr_vertex++; + active_vertex_index++; +} + +void im_cube(float length, vec3 position, quat rotation, vec4 color, int draw_mode) +{ + if(active_geom) + { + log_error("im_begin", "im_begin called before im_end"); + return; + } + IM_State.curr_geom++; + active_geom = &IM_State.geometries[IM_State.curr_geom]; + active_geom->type = IGT_PRIMITIVE; + active_geom->draw_mode = draw_mode; + active_geom->prim_geom_index = geom_create_from_file("cube.symbres"); + vec3_assign(&active_geom->position, &position); + vec3 scale = { length, length, length }; + vec3_assign(&active_geom->scale, &scale); + vec4_assign(&active_geom->color, &color); + quat_assign(&active_geom->rotation, &rotation); + active_geom = NULL; } -void im_color(float r, float g, float b, float a) +void im_sphere(float radius, vec3 position, quat rotation, vec4 color, int draw_mode) { - vec4_fill(&active_vertex_color, r, g, b, a); + if(active_geom) + { + log_error("im_begin", "im_begin called before im_end"); + return; + } + IM_State.curr_geom++; + active_geom = &IM_State.geometries[IM_State.curr_geom]; + active_geom->type = IGT_PRIMITIVE; + active_geom->draw_mode = draw_mode; + active_geom->prim_geom_index = geom_create_from_file("sphere.symbres"); + vec3_assign(&active_geom->position, &position); + vec3 scale = { radius, radius, radius }; + vec3_assign(&active_geom->scale, &scale); + quat_assign(&active_geom->rotation, &rotation); + vec4_assign(&active_geom->color, &color); + active_geom = NULL; } void im_end(void) { - active_geom->num_vertices = IM_State.curr_vertex - active_geom->start_index; + active_geom->num_vertices = active_vertex_index + 1; glBindBuffer(GL_ARRAY_BUFFER, IM_State.vbo); - glBufferSubData(GL_ARRAY_BUFFER, + GL_CHECK(glBufferSubData(GL_ARRAY_BUFFER, sizeof(struct IM_Vertex) * active_geom->start_index, sizeof(struct IM_Vertex) * active_geom->num_vertices, - &IM_State.vertices[active_geom->start_index]); - renderer_check_glerror("sprite_batch_end:glBufferSubData"); + &IM_State.vertices[0])); + glBindBuffer(GL_ARRAY_BUFFER, 0); active_geom = NULL; - vec4_assign(&active_vertex_color, &IM_State.default_color); + active_vertex_index = 0; + memset(&IM_State.vertices[0], 0, sizeof(struct IM_Vertex) * MAX_IM_VERTICES); } void im_render(struct Entity* active_viewer) @@ -121,31 +162,40 @@ void im_render(struct Entity* active_viewer) shader_bind(IM_State.im_shader); { - static mat4 mvp, translation, rotation, scale; - + static mat4 mvp, translation, rotation, scale; + glBindVertexArray(IM_State.vao); for(int i = 0; i <= IM_State.curr_geom; i++) { struct IM_Geom* geom = &IM_State.geometries[i]; - mat4_identity(&mvp); - - mat4_identity(&scale); - mat4_identity(&translation); - mat4_identity(&rotation); - - mat4_scale(&scale, geom->scale.x, geom->scale.y, geom->scale.z); - mat4_translate(&translation, geom->position.x, geom->position.y, geom->position.z); - mat4_from_quat(&rotation, &geom->rotation); - - mat4_mul(&mvp, &mvp, &translation); - mat4_mul(&mvp, &mvp, &rotation); - mat4_mul(&mvp, &mvp, &scale); - + mat4_identity(&mvp); + + mat4_identity(&scale); + mat4_identity(&translation); + mat4_identity(&rotation); + + mat4_scale(&scale, geom->scale.x, geom->scale.y, geom->scale.z); + mat4_translate(&translation, geom->position.x, geom->position.y, geom->position.z); + mat4_from_quat(&rotation, &geom->rotation); + + mat4_mul(&mvp, &mvp, &translation); + mat4_mul(&mvp, &mvp, &rotation); + mat4_mul(&mvp, &mvp, &scale); + mat4_mul(&mvp, &active_viewer->camera.view_proj_mat, &mvp); shader_set_uniform_mat4(IM_State.im_shader, "mvp", &mvp); - - glDrawArrays(geom->draw_mode, geom->start_index, geom->num_vertices); + shader_set_uniform_vec4(IM_State.im_shader, "geom_color", &geom->color); + if(geom->type == IGT_DYNAMIC) + { + glDrawArrays(geom->draw_mode, geom->start_index, geom->num_vertices); + } + else + { + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + geom_render(geom->prim_geom_index, geom->draw_mode); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + } } glBindVertexArray(0); diff --git a/src/libsymmetry/im_render.h b/src/libsymmetry/im_render.h index 5660405..9450910 100644 --- a/src/libsymmetry/im_render.h +++ b/src/libsymmetry/im_render.h @@ -6,7 +6,12 @@ struct IM_Vertex { vec3 position; - vec4 color; +}; + +enum IM_Geom_Type +{ + IGT_PRIMITIVE = 0, + IGT_DYNAMIC }; struct IM_Geom @@ -14,8 +19,18 @@ struct IM_Geom vec3 position; quat rotation; vec3 scale; - int start_index; - int num_vertices; + vec4 color; + int type; + union + { + struct + { + int start_index; + int num_vertices; + }; + int prim_geom_index; + + }; int draw_mode; }; @@ -23,9 +38,10 @@ struct Entity; void im_init(void); void im_cleanup(void); -void im_begin(vec3 position, quat rotation, vec3 scale, int draw_mode); +void im_begin(vec3 position, quat rotation, vec3 scale, vec4 color, int draw_mode); void im_pos(float x, float y, float z); -void im_color(float r, float g, float b, float a); // set active color +void im_cube(float length, vec3 position, quat rotation, vec4 color, int draw_mode); +void im_sphere(float radius, vec3 position, quat rotation, vec4 color, int draw_mode); void im_end(void); void im_render(struct Entity* active_viewer);