Explorar o código

add cube-based skybox (broken)

Ivan Avdeev %!s(int64=6) %!d(string=hai) anos
pai
achega
835011b1e2
Modificáronse 6 ficheiros con 149 adicións e 58 borrados
  1. 26 3
      src/bsp.c
  2. 11 1
      src/bsp.h
  3. 5 0
      src/common.h
  4. 107 5
      src/render.c
  5. 0 42
      src/texture.c
  6. 0 7
      src/texture.h

+ 26 - 3
src/bsp.c

@@ -736,6 +736,31 @@ static enum BSPLoadResult bspLoadModel(
 	return BSPLoadResult_Success;
 } // bspLoadModel()
 
+static const struct {
+	const char *suffix;
+	BSPSkyboxDir dir;
+} bsp_skybox_suffix[6] = {
+	{"rt", BSPSkyboxDir_RT},
+	{"lf", BSPSkyboxDir_LF},
+	{"ft", BSPSkyboxDir_FT},
+	{"bk", BSPSkyboxDir_BK},
+	{"up", BSPSkyboxDir_UP},
+	{"dn", BSPSkyboxDir_DN}};
+
+static void bspLoadSkybox(StringView name, ICollection *coll, Stack *tmp, struct BSPModel *model) {
+	char *zname = alloca(name.length + 3 + 7);
+	memset(zname, 0, name.length + 3 + 7);
+	memcpy(zname, "skybox/", 7);
+	memcpy(zname + 7, name.str, name.length);
+
+	Texture localtex;
+	renderTextureInit(&localtex.texture);
+	for (int i = 0; i < 6; ++i) {
+		memcpy(zname + name.length + 7, bsp_skybox_suffix[i].suffix, 2);
+		model->skybox[bsp_skybox_suffix[i].dir] = textureGet(zname, coll, tmp);
+	}
+}
+
 struct EntityProp {
 	const char *name;
 	const char *value;
@@ -860,12 +885,10 @@ enum BSPLoadResult bspReadEntityWorldspawn(struct BSPLoadModelContext *ctx, stru
 	if (result != BSPLoadResult_Success)
 		return result;
 
-	/* FIXME skyboxes cannot be cube maps ;_;
 	if (props[0].value_length > 0) {
 		const StringView sky = { props[0].value, props[0].value_length };
-		ctx->model->skybox = textureGetSkybox(sky, ctx->collection, ctx->persistent);
+		bspLoadSkybox(sky, ctx->collection, ctx->persistent, ctx->model);
 	}
-	*/
 
 	return BSPLoadResult_Success;
 }

+ 11 - 1
src/bsp.h

@@ -32,12 +32,22 @@ struct BSPDrawSet {
 	struct BSPDraw *draws;
 };
 
+typedef enum {
+	BSPSkyboxDir_RT,
+	BSPSkyboxDir_LF,
+	BSPSkyboxDir_FT,
+	BSPSkyboxDir_BK,
+	BSPSkyboxDir_UP,
+	BSPSkyboxDir_DN,
+	BSPSkyboxDir_COUNT
+} BSPSkyboxDir;
+
 struct BSPModel {
 	struct AABB aabb;
 	RTexture lightmap;
 	RBuffer vbo, ibo;
 
-	const struct Texture *skybox;
+	const struct Texture *skybox[BSPSkyboxDir_COUNT];
 
 	struct BSPDrawSet detailed;
 	struct BSPDrawSet coarse;

+ 5 - 0
src/common.h

@@ -9,3 +9,8 @@
 #define ASSERT(cond) if (!(cond)){PRINTF("%s failed", #cond); abort();}
 
 #define COUNTOF(a) (sizeof(a) / sizeof(*(a)))
+
+typedef struct {
+	const char *str;
+	int length;
+} StringView;

+ 107 - 5
src/render.c

@@ -202,7 +202,7 @@ void renderTextureUpload(RTexture *texture, RTextureUploadParams params) {
 	if (params.generate_mipmaps)
 		GL_CALL(glGenerateMipmap(binding));
 
-	GL_CALL(glTexParameteri(binding, GL_TEXTURE_MIN_FILTER, params.generate_mipmaps ? GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST));
+	GL_CALL(glTexParameteri(binding, GL_TEXTURE_MIN_FILTER, params.generate_mipmaps ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR));
 	GL_CALL(glTexParameteri(binding, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
 
 	GL_CALL(glTexParameteri(binding, GL_TEXTURE_WRAP_S, wrap));
@@ -269,6 +269,11 @@ RENDER_LIST_ATTRIBS
 	RENDER_DECLARE_UNIFORM(tex1) \
 	RENDER_DECLARE_UNIFORM(tex0_size) \
 	RENDER_DECLARE_UNIFORM(tex1_size) \
+	RENDER_DECLARE_UNIFORM(tex2) \
+	RENDER_DECLARE_UNIFORM(tex3) \
+	RENDER_DECLARE_UNIFORM(tex4) \
+	RENDER_DECLARE_UNIFORM(tex5) \
+	RENDER_DECLARE_UNIFORM(cam_pos) \
 
 static const RUniform uniforms[] = {
 #define RENDER_DECLARE_UNIFORM(n) {"u_" # n},
@@ -295,6 +300,7 @@ typedef struct RProgram {
 enum {
 	Program_LightmapColor,
 	Program_LightmapTexture,
+	Program_Skybox,
 	Program_COUNT
 };
 
@@ -316,7 +322,7 @@ static RProgram programs[Program_COUNT] = {
 			/*fragment*/
 			"uniform sampler2D u_lightmap;\n"
 			"void main() {\n"
-				"gl_FragColor = vec4(v_color * (vec3(.1) + texture2D(u_lightmap, v_lightmap_uv).xyz), 1.);\n"
+				"gl_FragColor = vec4(v_color * texture2D(u_lightmap, v_lightmap_uv).xyz, 1.);\n"
 			"}\n"
 			},
 		{ -1 }, { -1 }
@@ -343,15 +349,86 @@ static RProgram programs[Program_COUNT] = {
 		"vec4 albedo = texture2D(u_tex0, v_tex_uv/u_tex0_size);\n"
 		"albedo = mix(albedo, texture2D(u_tex1, v_tex_uv/u_tex1_size), .0);\n"
 		"vec3 lm = texture2D(u_lightmap, v_lightmap_uv).xyz;\n"
-		"vec3 color = albedo.xyz * (vec3(.1) + lm);\n"
+		"vec3 color = albedo.xyz * lm;\n"
 		"gl_FragColor = vec4(mix(color, tc, u_lmn), 1.);\n"
 	"}\n"
 			},
 		{ -1 }, { -1 }
 	},
+	/* Skybox */
+	{-1, { /* common */
+		"varying vec2 v_uv;\n"
+		"varying float texid;\n",
+		/* vertex */
+		"attribute vec3 a_vertex;\n"
+		"uniform vec3 u_cam_pos;\n"
+		"attribute vec2 a_tex_uv;\n"
+		"attribute vec2 a_lightmap_uv;\n"
+		"uniform mat4 u_mvp;\n"
+		"void main() {\n"
+			"v_uv = a_tex_uv;\n"
+			"texid = a_lightmap_uv.x;\n"
+			"gl_Position = u_mvp * vec4(u_cam_pos + 100000. * a_vertex, 1.);\n"
+		"}\n",
+		/* fragment */
+		"uniform sampler2D u_tex0, u_tex1, u_tex2, u_tex3, u_tex4, u_tex5;\n"
+		"void main() {\n"
+			"if (texid < 1.) gl_FragColor = texture2D(u_tex0, v_uv);\n"
+			"else if (texid < 2.) gl_FragColor = texture2D(u_tex1, v_uv);\n"
+			"else if (texid < 3.) gl_FragColor = texture2D(u_tex2, v_uv);\n"
+			"else if (texid < 4.) gl_FragColor = texture2D(u_tex3, v_uv);\n"
+			"else if (texid < 5.) gl_FragColor = texture2D(u_tex4, v_uv);\n"
+			"else gl_FragColor = texture2D(u_tex5, v_uv);\n"
+		"}\n"
+		}, {-1}, {-1}},
+};
 
+static struct BSPModelVertex box[] = {
+	{{ 1.f, -1.f, -1.f}, {0.f, 0.f}, {1.f, 0.f}, {0, 0, 0}},
+	{{ 1.f,  1.f, -1.f}, {0.f, 0.f}, {1.f, 1.f}, {0, 0, 0}},
+	{{ 1.f,  1.f,  1.f}, {0.f, 0.f}, {0.f, 1.f}, {0, 0, 0}},
+	{{ 1.f,  1.f,  1.f}, {0.f, 0.f}, {0.f, 1.f}, {0, 0, 0}},
+	{{ 1.f, -1.f,  1.f}, {0.f, 0.f}, {0.f, 0.f}, {0, 0, 0}},
+	{{ 1.f, -1.f, -1.f}, {0.f, 0.f}, {1.f, 0.f}, {0, 0, 0}},
+
+	{{-1.f, -1.f,  1.f}, {1.f, 0.f}, {1.f, 0.f}, {0, 0, 0}},
+	{{-1.f,  1.f,  1.f}, {1.f, 0.f}, {1.f, 1.f}, {0, 0, 0}},
+	{{-1.f,  1.f, -1.f}, {1.f, 0.f}, {0.f, 1.f}, {0, 0, 0}},
+	{{-1.f,  1.f, -1.f}, {1.f, 0.f}, {0.f, 1.f}, {0, 0, 0}},
+	{{-1.f, -1.f, -1.f}, {1.f, 0.f}, {0.f, 0.f}, {0, 0, 0}},
+	{{-1.f, -1.f,  1.f}, {1.f, 0.f}, {1.f, 0.f}, {0, 0, 0}},
+
+	{{ 1.f, -1.f,  1.f}, {2.f, 0.f}, {1.f, 0.f}, {0, 0, 0}},
+	{{ 1.f,  1.f,  1.f}, {2.f, 0.f}, {1.f, 1.f}, {0, 0, 0}},
+	{{-1.f,  1.f,  1.f}, {2.f, 0.f}, {0.f, 1.f}, {0, 0, 0}},
+	{{-1.f,  1.f,  1.f}, {2.f, 0.f}, {0.f, 1.f}, {0, 0, 0}},
+	{{-1.f, -1.f,  1.f}, {2.f, 0.f}, {0.f, 0.f}, {0, 0, 0}},
+	{{ 1.f, -1.f,  1.f}, {2.f, 0.f}, {1.f, 0.f}, {0, 0, 0}},
+
+	{{-1.f, -1.f, -1.f}, {3.f, 0.f}, {1.f, 0.f}, {0, 0, 0}},
+	{{-1.f,  1.f, -1.f}, {3.f, 0.f}, {1.f, 1.f}, {0, 0, 0}},
+	{{ 1.f,  1.f, -1.f}, {3.f, 0.f}, {0.f, 1.f}, {0, 0, 0}},
+	{{ 1.f,  1.f, -1.f}, {3.f, 0.f}, {0.f, 1.f}, {0, 0, 0}},
+	{{ 1.f, -1.f, -1.f}, {3.f, 0.f}, {0.f, 0.f}, {0, 0, 0}},
+	{{-1.f, -1.f, -1.f}, {3.f, 0.f}, {1.f, 0.f}, {0, 0, 0}},
+
+	{{ 1.f,  1.f,  1.f}, {4.f, 0.f}, {1.f, 0.f}, {0, 0, 0}},
+	{{ 1.f,  1.f, -1.f}, {4.f, 0.f}, {1.f, 1.f}, {0, 0, 0}},
+	{{-1.f,  1.f, -1.f}, {4.f, 0.f}, {0.f, 1.f}, {0, 0, 0}},
+	{{-1.f,  1.f, -1.f}, {4.f, 0.f}, {0.f, 1.f}, {0, 0, 0}},
+	{{-1.f,  1.f,  1.f}, {4.f, 0.f}, {0.f, 0.f}, {0, 0, 0}},
+	{{ 1.f,  1.f,  1.f}, {4.f, 0.f}, {1.f, 0.f}, {0, 0, 0}},
+
+	{{ 1.f, -1.f, -1.f}, {5.f, 0.f}, {1.f, 0.f}, {0, 0, 0}},
+	{{ 1.f, -1.f,  1.f}, {5.f, 0.f}, {1.f, 1.f}, {0, 0, 0}},
+	{{-1.f, -1.f,  1.f}, {5.f, 0.f}, {0.f, 1.f}, {0, 0, 0}},
+	{{-1.f, -1.f,  1.f}, {5.f, 0.f}, {0.f, 1.f}, {0, 0, 0}},
+	{{-1.f, -1.f, -1.f}, {5.f, 0.f}, {0.f, 0.f}, {0, 0, 0}},
+	{{ 1.f, -1.f, -1.f}, {5.f, 0.f}, {1.f, 0.f}, {0, 0, 0}},
 };
 
+static RBuffer box_buffer;
+
 static struct {
 	const RTexture *current_tex0;
 
@@ -359,6 +436,7 @@ static struct {
 	struct {
 		const float *mvp;
 		float lmn;
+		struct AVec3f campos;
 	} uniforms;
 } r;
 
@@ -389,9 +467,14 @@ static int render_ProgramUse(RProgram *prog) {
 	GL_CALL(glUniform1i(prog->uniform_locations[RUniformKind_lightmap], 0));
 	GL_CALL(glUniform1i(prog->uniform_locations[RUniformKind_tex0], 1));
 	GL_CALL(glUniform1i(prog->uniform_locations[RUniformKind_tex1], 2));
+	GL_CALL(glUniform1i(prog->uniform_locations[RUniformKind_tex2], 3));
+	GL_CALL(glUniform1i(prog->uniform_locations[RUniformKind_tex3], 4));
+	GL_CALL(glUniform1i(prog->uniform_locations[RUniformKind_tex4], 5));
+	GL_CALL(glUniform1i(prog->uniform_locations[RUniformKind_tex5], 6));
 
 	GL_CALL(glUniformMatrix4fv(prog->uniform_locations[RUniformKind_mvp], 1, GL_FALSE, r.uniforms.mvp));
 	GL_CALL(glUniform1f(prog->uniform_locations[RUniformKind_lmn], r.uniforms.lmn));
+	GL_CALL(glUniform3f(prog->uniform_locations[RUniformKind_cam_pos], r.uniforms.campos.x, r.uniforms.campos.y, r.uniforms.campos.z));
 
 	r.current_program = prog;
 	r.current_tex0 = NULL;
@@ -505,6 +588,8 @@ int renderInit() {
 		cachePutMaterial("opensource/coarse", &lightmap_color_material);
 	}
 
+	renderBufferCreate(&box_buffer, RBufferType_Vertex, sizeof(box), box);
+
 	GL_CALL(glEnable(GL_DEPTH_TEST));
 	GL_CALL(glEnable(GL_CULL_FACE));
 	return 1;
@@ -552,6 +637,21 @@ static void renderDrawSet(const struct BSPModel *model, const struct BSPDrawSet
 	}
 }
 
+static void renderBindTexture(const RTexture *texture, int slot) {
+	GL_CALL(glActiveTexture(GL_TEXTURE0 + slot));
+	GL_CALL(glBindTexture(GL_TEXTURE_2D, texture->gl_name));
+}
+
+static void renderSkybox(const struct BSPModel *model) {
+	render_ProgramUse(programs + Program_Skybox);
+	for (int i = 0; i < 6; ++i)
+		renderBindTexture(&model->skybox[i]->texture, 1+i);
+	renderApplyAttribs(attribs, &box_buffer, 0);
+	GL_CALL(glDisable(GL_CULL_FACE));
+	GL_CALL(glDrawArrays(GL_TRIANGLES, 0, COUNTOF(box)));
+	GL_CALL(glEnable(GL_CULL_FACE));
+}
+
 static float aMaxf(float a, float b) { return a > b ? a : b; }
 //static float aMinf(float a, float b) { return a < b ? a : b; }
 
@@ -559,13 +659,13 @@ void renderModelDraw(const struct AMat4f *mvp, struct AVec3f camera_position, fl
 	if (!model->detailed.draws_count) return;
 
 	GL_CALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, model->ibo.gl_name));
-	GL_CALL(glActiveTexture(GL_TEXTURE0));
-	GL_CALL(glBindTexture(GL_TEXTURE_2D, model->lightmap.gl_name));
+	renderBindTexture(&model->lightmap, 0);
 	GL_CALL(glActiveTexture(GL_TEXTURE0 + 1));
 
 	r.current_program = NULL;
 	r.uniforms.mvp = &mvp->X.x;
 	r.uniforms.lmn = lmn;
+	r.uniforms.campos = camera_position;
 
 	const float distance =
 		aMaxf(aMaxf(
@@ -582,6 +682,8 @@ void renderModelDraw(const struct AMat4f *mvp, struct AVec3f camera_position, fl
 		renderDrawSet(model, &model->detailed);
 	else
 		renderDrawSet(model, &model->coarse);
+
+	renderSkybox(model);
 }
 
 void renderResize(int w, int h) {

+ 0 - 42
src/texture.c

@@ -277,45 +277,3 @@ const Texture *textureGet(const char *name, struct ICollection *collection, stru
 	texfile->close(texfile);
 	return tex ? tex : cacheGetTexture("opensource/placeholder");
 }
-
-static const struct {
-	const char *suffix;
-	RTexType type;
-} texture_skybox_faces[6] = {
-	{"rt", RTexType_CubePX},
-	{"bk", RTexType_CubeNY},
-	{"dn", RTexType_CubeNZ},
-	{"ft", RTexType_CubePY},
-	{"lf", RTexType_CubeNX},
-	{"up", RTexType_CubePZ}};
-
-const Texture *textureGetSkybox(StringView name, ICollection *coll, Stack *tmp) {
-	char *zname = alloca(name.length + 3 + 7);
-	memset(zname, 0, name.length + 3 + 7);
-	memcpy(zname, "skybox/", 7);
-	memcpy(zname + 7, name.str, name.length);
-	const Texture *tex = cacheGetTexture(zname); /* FIXME will collide with non-skybox textures with the same name */
-	if (tex) return tex;
-
-	Texture localtex;
-	renderTextureInit(&localtex.texture);
-	for (int i = 0; i < 6; ++i) {
-		memcpy(zname + name.length + 7, texture_skybox_faces[i].suffix, 2);
-		struct IFile *texfile;
-		if (CollectionOpen_Success != collectionChainOpen(coll, zname, File_Texture, &texfile)) {
-			/* FIXME partially loaded skybox will leak here */
-			PRINTF("Texture \"%s\" not found", zname);
-			return cacheGetTexture("opensource/placeholder");
-		}
-
-		if (textureLoad(texfile, &localtex, tmp, texture_skybox_faces[i].type) == 0) {
-			/* FIXME partially loaded skybox will leak here */
-			texfile->close(texfile);
-			PRINTF("Texture \"%s\" found, but could not be loaded", zname);
-			return cacheGetTexture("opensource/placeholder");
-		}
-	}
-
-	cachePutTexture(zname, &localtex);
-	return cacheGetTexture(zname);
-}

+ 0 - 7
src/texture.h

@@ -9,10 +9,3 @@ typedef struct Texture {
 } Texture;
 
 const Texture *textureGet(const char *name, struct ICollection *collection, struct Stack *tmp);
-
-typedef struct {
-	const char *str;
-	int length;
-} StringView;
-
-const Texture *textureGetSkybox(StringView name, ICollection *coll, Stack *tmp);